Servlet介绍
概述
Servlet是运行在服务器端的Java应用程序
servlet程序开发动态资源的技术
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,
用Java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容。
作用:
用于接收和处理http请求(接收和响应请求)
最核心的方法
void service(ServletRequest req,ServletResponse res)
ServletRequest req 代表请求对象,包含请求的所有内容,用于获取请求数据
ServletResponse res 代表响应对象,包含响应的所有内容,用于修改响应数据
Servlet开发步骤
1)java类,继承HttpServlet类
覆盖doGet和doPost方法
2)在web应用web.xml中配置servlet
3)请求Servlet
创建Servlet
//第一种方式 继承 GenericServlet
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class OneServlet extends GenericServlet {
private static final long serialVersionUID = -2949013647446695209L;
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
}
}
//第二种方式 继承 HttpServlet
//继承自GenericServlet类,是在其基础上扩展了Http协议的Servlet
//会先调用service方法,然后根据请求方式来进行调用doGet/doPost
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class OneServlet extends HttpServlet {
private static final long serialVersionUID = -4435501112176421548L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
配置Servlet
在web.xml中配置
<servlet>
<!-- 名称要唯一 -->
<servlet-name>one</servlet-name>
<!-- 全路径 -->
<servlet-class>com.shuai.action.OneServlet</servlet-class>
</servlet>
<servlet-mapping>
<!-- 要与上边的名称一致 -->
<servlet-name>one</servlet-name>
<!-- 访问Servlet的URL,相对于Web应用的路径 -->
<url-pattern>/one</url-pattern>
</servlet-mapping>
配置Servlet中设置初始化值
<servlet>
<servlet-name>one</servlet-name>
<servlet-class>com.shuai.action.OneServlet</servlet-class>
<!-- 设置初始化值 -->
<init-param>
<param-name>initParam</param-name>
<param-value>paramtest</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>one</servlet-name>
<url-pattern>/one</url-pattern>
</servlet-mapping>
@Override
public void init(ServletConfig config) throws ServletException {
//这个super一定不要删掉
super.init(config);
//通过ServletConfig对象读取初始化参数
String initParameter = config.getInitParameter("initParam");
System.out.println(initParameter);
//获得所有参数的key
Enumeration<String> enumeration = config.getInitParameterNames();
}
有参的init 与 无参init
有参init:生命周期方法,必定会被服务器调用。(内部默认会调用无参的init方法)
无参init:提供给开发者进行初始化工作的方法。
Servlet生命周期
实例化 - Servlet 容器创建 Servlet 的实例
初始化 - 容器调用 init() 方法
请求处理 - 如果请求 Servlet,则容器调用 service() 方法
服务终止/重新部署 - 销毁实例之前调用 destroy() 方法,通过stop server看
Servlet线程安全问题
Servlet 在服务器中是单实例多线程的。
每次都会在Service方法中新建一个子线程来处理请求:new ThreadServlet()
引起并发问题的原因:在Servlet中使用了成员变量(多个线程共享的数据)。
测试:
可以通过在Servlet中输出一个count值,然后线程睡眠,最后count++。
用两个浏览器同时去访问。会发现最后输出的结果是一样的。
解决多并发,用同步
在doGet方法中
synchronized (OneServlet.class) {
//业务代码
}
建议:
尽量不要在Servlet中使用成员变量
如果使用了成员变量,那么就需要使用synchronized进行同步代码,而且尽量缩小同步的范围
Servlet的一些细节
改变Servlet的创建时机
<servlet>
<servlet-name>one</servlet-name>
<servlet-class>com.shuai.action.ThreeServlet</servlet-class>
<!-- 在项目部署启动的时候,默认创建Servlet,数值越大优先级越低 -->
<load-on-startup>1</load-on-startup>
</servlet>
路径映射规则
url-pattern 页面访问
精确映射 /one /one
/test/one /test/one
模糊映射 /* /任意路径
/test/* /test/任意路径
*.后缀 任意路径.后缀
注意:
url-pattern要么以/或者*开头
当前有多个url-pattern,优先级问题
后缀名结尾的url-pattern优先级最低
哪个更加精确哪个优先
ServletConfig对象
概述
Servlet配置对象
作用
用于读取servlet参数
如何得到ServletConfig对象
通过有参的init方法获得
通过getServletConfig()获得
ServletContext对象
概述
ServletContext是servlet的上下文对象。
代表当前web应用。
一个web有且只有一个ServletContext对象。
获取ServletContext对象
ServletContext servletContext = getServletConfig().getServletContext();
ServletContext servletContext = getServletContext();
作用
作为全局的域对象使用
读取全局的配置参数
转发web应用内的资源
读取web应用内的文件
具体使用
设置全局属性参数
ServletContext servletContext = getServletContext();
servletContext.setAttribute("name", "zhangsan");
String str = (String)servletContext.getAttribute("name");
读取全局参数
<!-- 全局参数 -->
<context-param>
<param-name>onep</param-name>
<param-value>onep</param-value>
</context-param>
<context-param>
<param-name>twop</param-name>
<param-value>twop</param-value>
</context-param>
ServletContext servletContext = getServletContext();
String onep = servletContext.getInitParameter("onep");
String twop = servletContext.getInitParameter("twop");
转发
ServletContext servletContext = getServletContext();
//转发内部资源
RequestDispatcher dispatcher = servletContext.getRequestDispatcher("info.jsp");
dispatcher.forward(req, res);
读取web应用内的文件
ServletContext servletContext = getServletContext();
//获取一个文件的绝对路径 - 获取的项目根目录
//要以/开头
String realPath = servletContext.getRealPath("/");
System.out.println(realPath);
//读取一个文件,并且返回一个文件流
InputStream inputStream = servletContext.getResourceAsStream("/路径");
HttpServletResponse对象
response对象
表示响应对象,包含所有的响应数据。使用response对象可以修改响应数据。
响应格式
响应行
http版本
状态码 setStatus(sc)方法
描述
响应头
键值对
setHeader(key,value)方法
setDateHeader(key,value)方法-专门修改日期类型的响应头
setIntHeader(key,value)方法 - 专门修改int类型的响应头
空行
正文
getWriter() 修改字符类型的正文(文本,网页)minetype:text/*类型
getOutputStream() 修改字节类型的正文(图片,视频)
getOutputStream()返回文本数据解决乱码
系统默认是GBK
ServletOutputStream outputStream = res.getOutputStream();
String str = "帅哥";
outputStream.write(str.getBytes());
输出其它编码
ServletOutputStream outputStream = res.getOutputStream();
第一种方式
仅仅在ie浏览器有效
String meta = "<meta http-equiv='content-type' content='text/html; charset=UTF-8'>";
//String meta = "<meta charset='UTF-8'>";
outputStream.write(meta.getBytes());
第二种方式
所有浏览器有效
response.setHeader("content-type", "text/html; charset=UTF-8");
第三种方式
所有浏览器有效
response.setContentType("text/html; charset=UTF-8");
String str = "帅哥";
outputStream.write(str.getBytes("UTF-8"));
getWriter()返回文本数据解决乱码
write方法默认是iso-8859-1
只能输出字节
输出其它编码
修改输出字符内容的查询编码-修改的是服务器- 这个代码可以省略
response.setCharacterEncoding("UTF-8");
通知浏览器使用正确的编码解析
response.setContentType("text/html; charset=UTF-8");
PrintWriter writer = response.getWriter();
默认编码是iso-8859-1
writer.write("帅哥");
文件下载
读取文件
String path = getServletContext().getRealPath("/file/开发0710学生情况.xlsx");
File file = new File(path);
FileInputStream inputStream = new FileInputStream(file);
获取输出通道
ServletOutputStream outputStream = response.getOutputStream();
下载提示框 响应头 content-disposition
注意:在浏览器和服务器之间请求头和响应头内容出现中文,不能直接传输,而应该把中文内容进行URL编码才能传输
String filename = URLEncoder.encode(file.getName(),"UTF-8");
response.setHeader("content-disposition", "attachment;filename="+filename);
边读边写
byte[] buf = new byte[1024];
int len = 0;
while((len =inputStream.read(buf))!= -1){
outputStream.write(buf);
}
关闭流
inputStream.close();
输出随机验证码(防止恶意注册和登录)
public void writeImage(HttpServletResponse response)throws ServletException, IOException {
//内存生成一张图片
int width = 120;
int height = 50;
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//修改图片背景
//得到画笔
Graphics graphics = image.getGraphics();
//绘制背景
graphics.setColor(Color.gray);
//绘制形状
graphics.fillRect(0, 0, width, height);
//设置字体
graphics.setFont(new Font("黑体", Font.ITALIC, 30));
//绘制数字
graphics.setColor(Color.BLACK);
String str = "1234";
graphics.drawString(str, 20, 25);
//设置随机干扰线
Random ran = new Random();
for(int i=1;i<=20;i++){
int x1 = ran.nextInt(width);
int y1 = ran.nextInt(height);
int x2 = ran.nextInt(width);
int y2 = ran.nextInt(height);
//随机色
graphics.setColor(getRanColor());
graphics.drawLine(x1, y1, x2, y2);
}
//把这个图片写出给浏览器
ServletOutputStream outputStream = response.getOutputStream();
ImageIO.write(image, "gif", outputStream);
}
//获取随机颜色
private Color getRanColor(){
Random ran = new Random();
int r = ran.nextInt(256);
int g = ran.nextInt(256);
int b = ran.nextInt(256);
return new Color(r,g,b);
}
页面使用
![](one)
重定向
发出两次请求
地址栏会发生变化
可以重定向任何资源(包括应用外的资源)
不可以通过request来共享数据
代码
response.sendRedirect("/info.jsp");
HttpServletRequest对象
概述
表示请求对象,包含所有的请求数据。使用request获取请求的数据。
请求格式
请求行
请求方式 request.getMethod()
请求资源 request.getRequestURL() / request.getRequestURI()
http版本 request.getProtocol()
获得get请求的参数 request.getQueryString()
请求头
获得一个请求头 getHeader(key)
获得整形的请求头 getIntHeader(key)
获得日期类型的请求头 getDateHeader(key)
空行
正文
获得正文 getInputStream()
防盗链
String referer = request.getHeader("referer");
if(referer == null || !referer.contains("/servlettest")){
//非法连接
return;
}
获取表单数据
get : getQueryString()
post : getInputStream()
通用方式
获取某个参数 getParameter("")
获取某个参数的集合 getParameterValues("") 例如:checkbox
获取所有的参数名 getParameterNames()
获取所有的参数 getParameterMap()
乱码问题
if("post".equalsIgnoreCase(request.getMethod())){
//只能解决post提交的参数,不能解决get提交的参数,因为这个方法只能设置请求正文的内容
request.setCharacterEncoding("UTF-8");
}
String name = request.getParameter("name");//默认是iso-8859-1
if("get".equalsIgnoreCase(request.getMethod())){
//get请求的参数需要手动解码
name = new String(name.getBytes("iso-8859-1"),"UTF-8");
}
转发
发出一次请求
地址栏不会发生变化
只能转发应用内的资源
可以通过request来共享数据
代码
//可以把数据发到转发的页面
req.setAttribute("name", "zhangshuai");
//第一种方式
getServletContext().getRequestDispatcher("/info.jsp").forward(req, response);
//第二种方式
req.getRequestDispatcher("/info.jsp").forward(req, response);
beanutils封装参数
下载
https://commons.apache.org/proper/commons-beanutils/
http://commons.apache.org/proper/commons-logging/ 依赖包
导包
commons-beanutils-1.9.3.jar
commons-logging-1.2.jar
页面
<form action="/easyuitest/one" method="post">
用户名:<input type="text" name="name" /><br />
密码:<input type="password" name="password" /><br />
爱好: <input type="checkbox" name="hobby" value="eat" />吃
<input type="checkbox" name="hobby" value="sleep" />睡
<input type="checkbox" name="hobby" value="play" />玩<br />
<input type="submit" value="提交" />
</form>
后台工具类
public static <T> T transform(Class clazz, HttpServletRequest req) throws Exception {
String method = req.getMethod();
if ("post".equalsIgnoreCase(method)) {
req.setCharacterEncoding("UTF-8");
}
Object instance = null;
instance = clazz.newInstance();
BeanUtils.populate(instance, req.getParameterMap());
if ("get".equalsIgnoreCase(method)) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String name = field.getName();
char charAt = name.charAt(0);
String upperCase = String.valueOf(charAt).toUpperCase();
String name2 = "set" + upperCase + name.substring(1);
String name1 = "get" + upperCase + name.substring(1);
Method method2 = clazz.getMethod(name2, field.getType());
Method method3 = clazz.getMethod(name1);
Class type = field.getType();
Class s = String.class;
String invoke = (String) method3.invoke(instance);
if (s.equals(type)) {
invoke = new String(invoke.getBytes("iso-8859-1"), "UTF-8");
}
method2.invoke(instance, invoke);
}
}
return (T) instance;
}
servlet中使用
User user = WebUtils.fillBean(request,User.class);
System.out.println(user);
注意
User中的属性一定要跟jsp中的属性一致。
原理
private void datatoentity(HttpServletRequest request) {
try {
//约定:表单的每个控件name属性值 和 需要封装的对象的属性名称保持一致!!
User user = new User();
//获取所有参数
Map<String,String[]> map = request.getParameterMap();
for(Entry<String,String[]> entry: map.entrySet()){
//参数名称(相当于对象的属性名)
String paramName = entry.getKey();
//参数值
String[] paramValue = entry.getValue();
//得到对象的属性(Field)
//得到类对象
Class clazz = user.getClass();
//获取类的某个属性(Field)
Field field = clazz.getDeclaredField(paramName);
//暴力反射
field.setAccessible(true);
//给属性赋值
//如果参数值有多个,则存入数组,否则存入数组的第一个元素
if(paramValue.length>1){
//赋值
field.set(user, paramValue);
}else{
field.set(user, paramValue[0]);
}
}
System.out.println(user);
}catch (Exception e) {
e.printStackTrace();
}
}
路径问题
浏览器行为 指向主机的根目录 tomcat/webapps
服务器行为 指向当前web应用的根目录 项目名称servlettest
服务端 项目根目录
服务器行为
getServletContext().getRealPath("/");
服务器行为
getServletContext().getResourceAsStream("/");
服务器行为
req.getRequestDispatcher("/");
服务器行为 /是否开头都一样
<%@ page errorPage="/" %>
服务器行为 /是否开头都一样
<%@ include file="/" %>
浏览器 tomcat/webapps目录
浏览器行为
resp.sendRedirect("/");
浏览器行为
/onetest/one 绝对路径,tomcat/webapps
one 相对路径,默认是项目根目录
<form action="/">
浏览器行为
/onetest/two 绝对路径,tomcat/webapps
two 相对路径,默认是项目根目录
<a href="/" />
浏览器行为
one.css 相对路径
/onetest/one.css 绝对路径
<link rel="stylesheet" type="text/css" href="/" />
浏览器行为
/onetest/info.js 绝对路径
info.js 相对路径,可以这样写,根目录就是项目 目录
<script type="text/javascript" src="/"></script>
浏览器行为-超链接
response.getWriter().write("<a href='/项目名/路径'>超链接</a>");
浏览器行为-表单
response.getWriter().write("<form action='/项目名/路径'></form>");
会话管理
概述
好比是一次通话。从打开浏览器,访问多次服务器资源,关闭浏览器,这个过程就一次会话。
是客户与Web服务器间一连串的交互过程。
会话管理就是解决多个请求数据共享的问题。
例如:多个用户使用浏览器与服务器进行会话的过程中,服务器怎样会每个用户保存这些数据。
两种技术
Cookie技术:客户端技术,数据是保存在浏览器的缓存中
定义:Cookie是一些数据,从Servlet发给浏览器,在浏览器中保存,然后通过浏览器发回给服务器。
属性:
name : cookie的名称
value : cookie的数据
comment : 注释
path : 保存的路径
domain : 保存的主机
maxAge : cookie存活的时间
负数:Cookie存活在浏览器内存,浏览器关闭Cookie丢失
正数:Cookie存活在缓存文件中,只有删除缓存文件Cookie才会丢失。
零 :立即过期,用于删除同名的Cookie
version : cookie的版本
servlet方法
添加 addCookie()
接收 getCookies()
限制
1)类型必须是字符串
2)cookie的长度不能超过4k,一个网站1次只能最多发20个,所有网站一共发300个
3)数据保存浏览器,安全性差
优点
利用浏览器资源,减轻服务器压力
HttpSession技术:服务器端技术,数据时保存在服务器内存中的
是一个域对象
获取方式
HttpSession session = request.getSession();
常用方法
setAttribute(key,value)
getAttribute(key)
特点
增加服务器压力
任意数据类型
大小没有限制
相对安全
Cookie
创建Cookie
Cookie cookie = new Cookie("name","shuaige");
/*
* 设置Cookie存活时间
* 负数:Cookie存活在浏览器内存,浏览器关闭Cookie丢失
* 正数:Cookie存活在缓存文件中,只有删除缓存文件Cookie才会丢失。
* 零 :立即过期,用于删除同名的Cookie
* */
cookie.setMaxAge(Integer.MAX_VALUE);
//默认路径 /项目名
cookie.setPath("/servlet/servlettest");
//发送给浏览器
response.addCookie(cookie);
每次浏览器请求会默认带着Cookie
//接收Cookie
//注意什么情况可以取出Cookie发送到服务器? 获取Cookie路径.startWith(Cookie的保存路径)=true的情况下可以获取。
//注意:如果把Cookie的保存路径设置为当前Web应用的根目录,那么在当前web应用下所有访问资源时都能取出该Cookie
Cookie[] cookies = request.getCookies();
for(int i = 0;i<cookies.length;i++){
Cookie cookie1 = cookies[i];
System.out.println(cookie1);
}
获取用户上次访问的时间
用Cookie来记录浏览过的商品
domain表示的是cookie所在的域,默认为请求的地址
同域访问
http://bbs.shuaige.com/onttest/one的默认域名是bbs.shuaige.com
跨域访问
http://bbs.shuaige.com/onttest/one
http://aas.shuaige.com/onetest/one
设置domain为.shuaige.com就可以跨域访问了。
本域设置不可以访问的
例如http://bbs.shuaige.com/onttest/one设置不可以访问,并且http://aas.shuaige.com/onetest/one可以访问的
设置domain为aas.shuaige.com就可以跨域访问了。
path是cookie所在目录
浏览器会将domain和path都相同的cookie保存在一个文件里,cookie间用*隔开
HttpSession
存值
//获取session
HttpSession session = request.getSession();
//把数据存到session中
session.setAttribute("name", "shuaige");
取值
//获取session
HttpSession session = request.getSession();
//把数据从session中取出
String name = (String)session.getAttribute("name");
System.out.println(name);
request.getSession()方法
1.查询服务器中是否存在对应的HttpSession对象
有:返回对应的对象
没有:创建一个新的对象返回
2.HttpSession对象会设置一个对应浏览器的JSESSINOID,通过请求头(set-cookie)实现。
HttpSession session = request.getSession();
String sid = session.getId();
服务器也是根据这个JSESSINOID来取出对应的session
3.注意:
request.getSession(true)/request.getSession()
查询服务器中是否存在对应的HttpSession对象
有:返回对应的对象
没有:创建一个新的对象返回
request.getSession(false)
查询服务器中是否存在对应的HttpSession对象
有:返回对应的对象
没有:返回null
原理
HttpSession对象会设置一个对应浏览器的JSESSINOID,通过请求头(set-cookie)实现。
HttpSession session = request.getSession();
String sid = session.getId();
服务器也是根据这个JSESSINOID来取出对应的session
购物车
会员登录
HttpSession钝化与激活
正常关闭服务
HttpSession对象过久没有访问
第三方控件-上传
概述
由非软件提供商提供的功能组件
commons-fileupload文件上传组件
Apache提供的实现文件上传的组件
免费的、开源的
commons-fileupload API
FileItemFactory接口
用于构建FileItem实例
DiskFileItemFactory类
是FileItemFactory接口实现类
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload类
组件的核心类
封装表单元素并以集合方式返回
ServletFileUpload(FileItemFactory fileitemfactory)
boolean isMultipartContent (HttpServletRequest request)
静态方法。用于判断请求数据中的内容是否是multipart/form-data类型。是返回true,否返回false
List parseRequest(HttpServletRequest request)
将请求数据中的每一个字段,单独封装成FileItem对象,并以List方式返回
FileItem类
封装表单元素的数据
具有对表单内容处理的方法
常用方法
String getFieldName() 返回表单字段元素的name属性值
boolean isFormField() 判断FileItem封装的数据是属于普通表单字段,或者是文件表单字段。普通表单字段:true,文件表单字段:false。
String getName() 返回上传文件字段中的文件名,文件名通常是不含路径信息的,取决于浏览器实现
void write(File file) 将FileItem对象中的内容保存到指定文件中
String getString() 按照默认编码格式返回字符串
String getString(String encoding) 按照指定编码格式将内容转换成字符串返回
使用步骤
1.获取commons-fileupload组件
commons-fileupload-版本号.jar
commons-io-版本号.jar
2.导入jar包
3.设置表单提交属性
<form name="form1" method="post" enctype="multipart/form-data" />
4.实现Servlet中的上传
4.1判断请求数据中的内容是否是multipart/form-data类型ServletFileUpload.isMultipartContent(req)
4.2创建FileItemFactory实例new DiskFileItemFactory()
4.3创建ServletFileUpload实例new ServletFileUpload(factory)
4.4解析request请求,获取表单元素对应的FileItem集合upload.parseRequest(req)
4.5循环遍历获取数据
4.6判断元素类型,true-普通表单元素,false-文件元素item.isFormField()
4.7如果是文件元素
4.7.1获取文件名称item.getName()
4.7.2如果有名称乱码就处理乱码new String(name.getBytes("GBK"),"UTF-8")
4.7.3写出到指定位置item.write(file)
代码
<form action="one" enctype="multipart/form-data" method="post">
<input name="username" type="text"/>
<input name="file" type="file" />
<input type="submit" value="提交">
</form>
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
if(isMultipart){
//创建FileItemFactory实例
//参数一:代表缓存大小。假如设置的大小是1M,如果上传的文件不超过1M,那么不用缓存,如果超过1M,就使用缓存
//参数二:代表缓存的目录。
//DiskFileItemFactory factory = new DiskFileItemFactory(1024*1024,new File("C:\\tempFiles"));
FileItemFactory factory = new DiskFileItemFactory();
//创建ServletFileUpload实例
ServletFileUpload upload = new ServletFileUpload(factory);
try {
//限制文件大小(限制单个文件不超过200KB,总文件大小不超过500KB)
//upload.setFileSizeMax(200*1024);//限制单个文件不超过200KB
//upload.setSizeMax(500*1024);//总文件大小不超过500KB
List<FileItem> list = upload.parseRequest(req);
for(FileItem item : list){
if(!item.isFormField()){
//限制文件类型(只能上传图片文件) mime类型: text/plain image/*
String contentType = item.getContentType();
if(!contentType.matches("image/[a-zA-Z]+")){
request.setAttribute("msg", "只允许上传图片格式的文件!");
request.getRequestDispatcher("/upload4.jsp").forward(request, response);
return;
}
String name = item.getName();
name = new String(name.getBytes("GBK"),"UTF-8");
String savePath = "f:\\"+name;
File file = new File(savePath);
item.write(file);
}else{
System.out.println("表单元素:"+item.getFieldName()+"-"+item.getString());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
分页
优势
数据能够按照指定格式显示,布局清晰
不受信息数量的限制
不足
当数据量较多,页面显示不完全时,需要用户拖动页面才能浏览更多信息
实现
Dao中
1.获取表中数据总条数 int getCount();
2.获取指定显示的条目 List<User> getUser(int start,int count);
Service中
1.每页显示条目个数
int pagenum = 6;
2.计算页数int getTotalPageCount()
public int getTotalPageCount(){
int count = getCount();
int num = count / pagenum;
if(count%pagenum != 0){
num = num+1;
}
return num;
}
3.获取指定显示的条目
public List<User> getUsers(int pageIndex){
int start = (pageIndex-1)*pagenum;
List<User> user = userDao.getUser(start, pagenum);
return user;
}
Controller中
1.获取页面总条目
String totalPageCountStr = req.getParameter("totalPageCount");
int totalPageCount = 0;
if(totalPageCountStr != null){
totalPageCount = Integer.valueOf(totalPageCountStr);
}else{
totalPageCount = service.getTotalPageCount();
}
2.获取当前显示多少页
String pageIndexStr = req.getParameter("pageIndex");
int pageIndex = 1;
if(pageIndexStr != null){
pageIndex = Integer.valueOf(pageIndexStr);
}
3.获取需要显示的数据
List<User> users = service.getUsers(pageIndex);
4.设置返回参数
req.setAttribute("pageIndex", pageIndex);
req.setAttribute("totalPageCount", totalPageCount);
req.setAttribute("users",users);
jsp中
显示数据
<table border="1">
<tr>
<th>id</th>
<th>name</th>
<th>age</th>
</tr>
<c:forEach items="${users}" var="user">
<tr>
<td>${user.id }</td>
<td>${user.name }</td>
<td>${user.age }</td>
</tr>
</c:forEach>
</table>
显示所有页数的链接
<%
int totalPageCount = (Integer)request.getAttribute("totalPageCount");
int pageIndex = (Integer)request.getAttribute("pageIndex");
for(int i = 1;i<=totalPageCount;i++){
StringBuffer sb = new StringBuffer();
if(i == pageIndex){
sb.append("<a style='padding: 5px;'>");
}else{
sb.append("<a href='one?pageIndex=");
sb.append(i);
sb.append("&totalPageCount=");
sb.append(totalPageCount);
sb.append("' style='padding: 5px;'>");
}
sb.append(i);
sb.append("</a>");
out.write(sb.toString());
}
%>
Servlet注解配置
@WebServlet("/login")
手动文件上传
//1)读取请求正文
InputStream in = request.getInputStream();
//2)转换为字符读取流
BufferedReader br = new BufferedReader(new InputStreamReader(in));
//3)第一行:读取文件的分割符
String fileTag = br.readLine();
//4)第二行:读取文件名称
String line = br.readLine();
String fileName = line.substring( line.lastIndexOf("filename=\"")+10 , line.length()-1);
//跳过两行
br.readLine();
br.readLine();
//5)读取文件内容
String str = null;
BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\targetFiles\\"+fileName));
//不断读取
while( (str=br.readLine())!=null ){
//忽略文件的分割符
if( (fileTag+"--").equals(str)){
break;
}
bw.write(str);//写出一行
bw.newLine();//换行符
}
bw.close();
br.close();