Filter
Filter:一个实现了特殊接口(Filter)的Java类. 实现对请求资源(jsp,servlet,html,)的过滤的功能.
过滤器是一个运行在服务器的程序(项目里面包含了过滤器,只要发布(启动)了项目,过滤器就会运转),优先于请求资源(Servlet或者jsp,html)之前执行. 过滤器是javaweb技术中最为实用的技术.
过滤器的作用
对目标资源(Servlet,jsp)进行过滤.
应用场景:登录权限检查,解决网站中文编码统一,过滤敏感字符 ...
通过xml配置方式
/*
1. 实现接口Filter
2. 注册过滤器 , web.xml
*/
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
public class DemoFilter01 implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("DemoFilter01::init~!");
//假设存在这样的需求,就是在这个init方法里面读取某个文件的内容。
//但是又不想直接在init方法里面硬编码写死这个文件的名字,此时可以使用初始化参数来配置文件的名字
String fileName = filterConfig.getInitParameter("fileName");
System.out.println("fileName=" + fileName);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("DemoFilter01::doFilter~!");
}
@Override
public void destroy() {
System.out.println("DemoFilter01::destroy~!");
}
}
web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--注册DemoFilter01-->
<filter>
<filter-name>demo01</filter-name>
<filter-class>com.zml.filter.demo.DemoFilter</filter-class>
<!--配置初始化参数-->
<init-param>
<param-name>fileName</param-name>
<param-value>C:/aa/bb/cc.jpg</param-value>
</init-param>
</filter>
<!--以后只要浏览器打过来这个地址: localhost:8080/项目映射名/aa-->
<filter-mapping>
<filter-name>demo01</filter-name>
<url-pattern>/aa</url-pattern>
</filter-mapping>
</web-app>
通过注解方式
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/bb")
public class DemoFilter02 implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("DemoFilter02::init~!");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("DemoFilter02::doFilter~!");
}
@Override
public void destroy() {
System.out.println("DemoFilter02::destroy~!");
}
}
Filter的生命周期
生命周期方法
init(FilterConfig):初始化 服务器启动的时候, 会调用init()方法进行初始化【调用一次】
doFilter(ServletReqeust req,ServletResponse resp,FilterChain chain):执行过滤的方法 任何一次请求都会调用doFilter()方法进行过滤【路径相匹配】
destroy():销毁 服务器正常关闭或者项目从服务器移除, 调用destroy()方法进行销毁【调用一次】
Filter的拦截方式
我们可以控制过滤器过滤指定的内容,但是我们在访问资源的时候,并不是每次都是直接访问,有时是以转发的方式访问的 (过滤器默认不过滤请求转发。),这就需要我们要让过滤器可以区分不同的访问资源的方式,有不同的拦截方式。 通过 DispatcherType 来指定的.
一般情况下, 转发我们不会过滤的. 转发属于服务器内部的行为. 直接使用默认值的情况偏多
DispatcherType.REQUEST
默认值,默认情况下,过滤器只会拦截浏览器发出来的请求。但是如果是一个Servlet请求转发跳转到另一个Servlet,这段跳转,过滤器默认不会过滤。
DispatcherType.FORWARD
只过滤转发过来的请求
/*@WebFilter("/*") urlpatterns : 对应就是这个过滤器它想过滤的资源请求路径 dispatcherTypes :过滤的方式。默认只会过滤浏览器过来的请求: DispatcherType.REQUEST 如果还想过滤请求转发的请求,需要额外加上 DispatcherType.FORWARD*/ @WebFilter(urlPatterns = "/*" ,dispatcherTypes= {DispatcherType.REQUEST,DispatcherType.FORWARD}) public class DemoFilter07 implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("DemoFilter07::init~!"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("DemoFilter07::doFilter~!"); //放行 filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { System.out.println("DemoFilter07::destroy~!"); } }
过滤器链
过滤器链机制:当一个filter收到请求的时候,调用chain.doFilter 放行才可以访问下一个匹配的filter,若当前的filter是最后一个filter,调用chain.doFilter 放行才能访问目标资源 。 前一个过滤器不放行,那么请求不会到达下一个过滤器或者目标资源
过滤器链执行顺序
配置文件: 谁先配置
filter-mapping
谁先执行注解方式: 按照Filter的首字母顺序 eg: AFilter BFilter A在B的前面, AFilter先执行
非法字符过滤案例
@WebServlet("/data/comment")
public class CommentServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("CommentServlet...doGet...");
//1. 获取要发布的评论内容
String comment = req.getParameter("comment");
//2. 直接输出到页面上
resp.getWriter().write("您发布的评论是:"+ comment);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("CommentServlet...doPost...");
doGet(req, resp);
}
}
/*
1. 拷贝敏感词汇文件到项目里面的web文件夹下
2. 在init方法里面读取敏感词汇文件 ServletContext
3. 把文件的内容保存到一个List集合中
*/
@WebFilter("/data/*")
public class CommentFilter implements Filter{
static List<String> wordsList = new ArrayList<>();
@Override
public void init(FilterConfig filterConfig) throws ServletException {
try {
System.out.println("CommentFilter::init~!");
//1. 得到servletcontext
ServletContext servletContext = filterConfig.getServletContext();
//2. 读取文件
InputStream is = servletContext.getResourceAsStream("IllegalWords.txt");
//3. 使用bufferreader来包装is ,以便可以按行来读内容 , 如果有中文,需要指定编码
BufferedReader br = new BufferedReader(new InputStreamReader(is , "utf-8"));
//4. 开始读取每一行
String line ;
while( (line = br.readLine()) != null){
//5. 把每一行都装到集合list里面
wordsList.add(line);
}
//6. 关闭流
br.close();
System.out.println("list=" + wordsList);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("CommentFilter::doFilter~!");
//1. 获取先要发布的评论内容
String comment = servletRequest.getParameter("comment");
//2. 判定是否含有敏感词汇
for(String word :wordsList){
if(comment.contains(word)){
//有敏感词汇
servletResponse.getWriter().write("含有敏感词汇,禁止发表!");
return;
}
}
//3. 如果没有敏感词汇,就直接放行
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
System.out.println("CommentFilter::destroy~!");
}
}
Listener
监听器就是一个Java类,用来监听 其他的JavaBean对象的变化
在javaweb中监听器就是监听三个作用域对象的状态的。request,session,servletContext(application),
说的具体一些就是监听这三个对象的创建和销毁,还有session里面的数据变化(钝化和活化)
JavaWeb的监听器使用步骤
创建一个类实现ServletContextListener
在web.xml配置 | 在类上使用注解配置(只要配置一次即可)
import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; /* 1. 定义一个类,实现接口 ServletContextListener 2. 实现方法: contextInitialized: servletcontext创建的时候调用, 项目发布的时候, contextDestroyed: servletcontext销毁的时候调用, 项目从服务器中移除,服务器关闭了 3. 注册|配置 监听器 注解: @WebListener xml: <listener> <listener-class>com.itheima.listener.MyServletContextListener</listener-class> </listener> */ @WebListener public class MyServletContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("contextInitialized..."); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("contextDestroyed..."); } }
web.xml文件配置
<listener> <listener-class>com.itheima.listener.MyServletContextListener</listener-class> </listener>
发送邮件案例
需要使用jar包: mail.jar
import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import java.util.Properties; public class SendMessages { public static void Send(String tittle,String value) throws MessagingException { Properties properties = new Properties(); properties.put("mail.transport.protocol", "smtp"); // 连接协议 properties.put("mail.smtp.host", "smtp.qq.com"); // 主机名 properties.put("mail.smtp.port", 465); // 端口号 // properties.put("mail.smtp.auth", "true"); // 需要验证 QQ邮箱开启后会发送到垃圾箱中 properties.put("mail.smtp.ssl.enable", "true"); // 是否启用ssl认证 properties.put("mail.debug", "true"); // 调试信息 // 得到会话对象 Session session = Session.getInstance(properties); // 获取邮件对象 Message mimeMessage = new MimeMessage(session); // 设置发件人 mimeMessage.setFrom(new InternetAddress("247321017@qq.com")); // 设置收件人 mimeMessage.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress("123456@qq.com")); // 设置邮件主题 mimeMessage.setSubject(tittle); // 设置邮件内容 mimeMessage.setText(value); // 得到邮件传输对象 Transport transport = session.getTransport(); // 连接自己的邮箱账户 transport.connect("247321017@qq.com", "qzznvklcxxxxxxx"); // 密码为QQ邮箱提供的授权码 // 发送邮件 transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients()); }
MD5加密算法
package com.example.basic;
import java.security.MessageDigest;
/**
* 写一个MD5算法,运行结果与MySQL的md5()函数相同
* 将明文密码转成MD5密码
* 123456->e10adc3949ba59abbe56e057f20f883e
*/
public class Md5Util {
private Md5Util(){}
/**
* 将明文密码转成MD5密码
*/
public static String encodeByMd5(String password) throws Exception{
//Java中MessageDigest类封装了MD5和SHA算法,今天我们只要MD5算法
MessageDigest md5 = MessageDigest.getInstance("MD5");
//调用MD5算法,即返回16个byte类型的值
byte[] byteArray = md5.digest(password.getBytes());
//注意:MessageDigest只能将String转成byte[],接下来的事情,由我们程序员来完成
return byteArrayToHexString(byteArray);
}
/**
* 将byte[]转在16进制字符串
*/
private static String byteArrayToHexString(byte[] byteArray) {
StringBuffer sb = new StringBuffer();
//遍历
for(byte b : byteArray){//16次
//取出每一个byte类型,进行转换
String hex = byteToHexString(b);
//将转换后的值放入StringBuffer中
sb.append(hex);
}
return sb.toString();
}
/**
* 将byte转在16进制字符串
*/
private static String byteToHexString(byte b) {//-31转成e1,10转成0a,。。。
//将byte类型赋给int类型
int n = b;
//如果n是负数
if(n < 0){
//转正数
//-31的16进制数,等价于求225的16进制数
n = 256 + n;
}
//商(14),数组的下标
int d1 = n / 16;
//余(1),数组的下标
int d2 = n % 16;
//通过下标取值
return hex[d1] + hex[d2];
}
private static String[] hex = {"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
/**
* 测试
*/
public static void main(String[] args) throws Exception{
String password = "123456";
String passwordMD5 = Md5Util.encodeByMd5(password);
System.out.println(password);
System.out.println(passwordMD5);
}
}
综合练习CRUD
注册登录添加查询功能
基础对象的创建
// 数据库表对应的对象 public class LinkMan implements Serializable{ private int id; private String name; private String sex; private int age; // get set 有参 无参构造方法 } // 分页查询数据封装对象 public class PageBean<T> { private List<T> list; //联系人列表 private int curPage;//当前页码 private int sumPage;//总页码 private int count;//总数量 private int curSize;//一页显示的数量 }
web层代码
@WebServlet("/linkManServlet") public class LinkManServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //0.处理乱码 request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); //1.获得method请求参数 String methodStr = request.getParameter("method"); // 使用反射的方式调用方法 // 获取现在要请求的是什么动作|方法,获取method的值 String methodName = req.getParameter("method"); //这个method其实就是方法名! //2. 由于method 从页面上传递过来的其实就是方法名 // 如果是查询所有,那么传递过来的是 findAll // 如果是添加联系人,页面传递过来的是add //有了方法名就可以直接调用方法。有对象才能调用。 //2.1 使用方法名,在当前这个类上找到方法。 //使用反射去找方法的时候,除了要写对方法的名字之外,还要写对方法的参数类型。 // this : 当前这个类的对象 this.getClass 得到这个类的字节码 //getMethod 就表示要在这个类上找它的一个方法 // 参数一: 方法名字 //参数二: 这个方法需要的第一个参数的类型 //参数三: 这个方法需要的第二个参数的类型。 Method m = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); //2.2 调用方法 //m 就是刚才找到的方法 //m.invoke 是一种反射调用的写法 // 参数一: 调用这个方法使用的对象是什么, this. // 参数二: 调用这个方法需要用到的参数 req // 参数三: 调用这个方法需要用到的第二个参数 resp m.invoke(this , req, resp); } catch (Exception e) { e.printStackTrace(); } /* //2. 判定到底想要执行的是什么方法 if("findAll".equals(method)){ findAll(req, resp); //执行查询所有的方法 }else if("add".equals(method)){ add(req,resp); //执行添加方法 }else if("delete".equals(method)){ delete(req , resp); //执行删除方法 }else if("findByPage".equals(method)){ findByPage(req,resp); }*/ } //删除联系人 public void delete(HttpServletRequest request,HttpServletResponse response){ try { //1. 获取参数 int id = Integer.parseInt(req.getParameter("id")); //2. 交代service LinkManService service = new LinkManService(); int row = service.delete(id); //3. 响应 if(row > 0){ //删除成功 //跳转到列表页面显示最新的数据,但是切忌直接跳转到list.jsp页面 findAll(req, resp); } } catch (SQLException throwables) { throwables.printStackTrace(); } } //查询所有的联系人 public void findAll(HttpServletRequest request,HttpServletResponse response){ try { //如果想要在这个方法上存值,或者跳转页面。 //1. 获取参数 ,由于是查询所有的联系人,所以这一步不用写! //2. 调用service。 LinkManService service = new LinkManService(); List<LinkMan> list = service.findAll(); //3. 响应 //3.1 先把list集合存到作用域里面去 request作用域 | session作用域 req.setAttribute("list", list); //3.2 跳转到list.jsp : 请求转发,重定向 req.getRequestDispatcher("list.jsp").forward(req, resp); } catch (Exception e) { e.printStackTrace(); } } //添加联系人 public void add(HttpServletRequest request,HttpServletResponse response){ try { //1. 获取所有参数 Map<String, String[]> map = req.getParameterMap(); //1.1 把map的数据封装到对象中。 LinkMan linkMan = new LinkMan(); BeanUtils.populate(linkMan , map); //2. 交代service干活 LinkManService service = new LinkManService(); int row = service.add(linkMan); //3. 响应 ,判定结果 if(row > 0 ){ //添加成功 //跳转到list.jsp页面,显示最新的数据。 添加完毕之后不能直接跳转到到list.jsp页面, // 因为没有查询数据,所以页面不会有任何显示。 //req.getRequestDispatcher("list.jsp").forward(req, resp); findAll(req,resp); } } catch (Exception e) { e.printStackTrace(); } } //分页展示联系人 public void findByPage(HttpServletRequest req, HttpServletResponse resp){ try { //0. 一开先设置好默认展示第1页,每页展示5条记录。 int currentPage = 1; int pageSize = 2; /* 1. 获取参数 1.1 有时候可以不用携带参数过来,有时候也可以携带参数过来 1.2 比如在index.jsp里面的分页入口,就可以不用携带参数 1.3 比如在分页列表页面上,允许用户选择:想看其中的第几页,每页想看多少条。 1.4 为了能够匹配更多的情况,这里的就需要获取参数。 1.5 如果也面有传递想看第几页,每页想看多少条,那么就是用页面传递过来的,否则就使用默认定义的。 */ String currentPageStr = req.getParameter("currentPage"); //想看第几页 String pageSizeStr = req.getParameter("pageSize"); //每页想看几条。 if(currentPageStr != null){ currentPage = Integer.parseInt(currentPageStr); } if(pageSizeStr!= null){ pageSize = Integer.parseInt(pageSizeStr); } //2. 交代service干活 LinkManService service = new LinkManService(); PageBean<LinkMan> pageBean = service.findByPage(currentPage , pageSize); //3. 响应 //3.1 把pageBean存到作用域 req.setAttribute("pageBean" , pageBean); //3.2 跳转到list_page.jsp显示数据 req.getRequestDispatcher("list_page.jsp").forward(req, resp); } catch (Exception e) { e.printStackTrace(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
Service层代码
public List<LinkMan> findAll() throws SQLException { //创建dao对象 LinkManDao dao = new LinkManDao(); //调用findAll方法~ return dao.findAll(); } public int add(LinkMan linkMan) throws SQLException { //调用Dao的add方法! LinkManDao dao = new LinkManDao(); return dao.add(linkMan); } public int delete(int id) throws SQLException { //调用dao的delete方法 LinkManDao dao = new LinkManDao(); return dao.delete(id); } /** * 分页查询联系人 * @param currentPage 想看第几页 * @param pageSize 每页想看多少条 * @return PageBean 里面封装了当前页的集合数据以及页码使用的信息。 */ public PageBean<LinkMan> findByPage(int currentPage , int pageSize) throws SQLException { //1. 创建PageBean对象 PageBean<LinkMan> pageBean = new PageBean<LinkMan>(); //1.1 调用dao,准备数据 LinkManDao dao = new LinkManDao(); // 获取当前这一页的集合数据 List<LinkMan> list = dao.findByPage(currentPage, pageSize); // 总记录数 101 int totalSize = dao.findCount(); //向上取整计算总页数: 101/10 = 10.1 ---> 11 10.9 ----> 11 // int totalPage = (int) Math.ceil(totalSize * 1.0 / pageSize); int totalPage = ((totalSize -1) / pageSize) + 1; //2. 封装PageBean pageBean.setPageSize(pageSize); //每页显示个数 10 pageBean.setTotalSize(totalSize); //总记录数,代表就是这张LinkMan表有多少条记录。 pageBean.setCurrentPage(currentPage); //当前页是第几页 pageBean.setTotalPage(totalPage); // 总共多少页 pageBean.setList(list); //当前这一页的集合数据 return pageBean; }
Dao层代码
public List<LinkMan> findAll() throws SQLException { //创建QueryRunner对象 QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource()); //定义Sql语句 String sql = "select * from linkman"; //执行查询,由于查询所有,所以得到的数据很多,那么必须要传的是BeanListHandler。 return runner.query(sql ,new BeanListHandler<LinkMan>(LinkMan.class)); } public int add(LinkMan linkMan) throws SQLException { //创建QueryRunner对象 QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource()); //定义Sql语句 String sql = "insert into linkman values(null,?,?,?)"; //执行添加 return runner.update(sql, linkMan.getName() , linkMan.getSex() ,linkMan.getAge()); } public int delete(int id ) throws SQLException { //创建QueryRunner QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource()); //删除语句 String sql = "delete from linkman where id = ?"; //执行删除 return runner.update(sql , id ); } //==============下面的两个方法专门用来做分页的================== /** * 返回linkMan表的总记录数 * @return */ public int findCount() throws SQLException { QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource()); String sql = "select count(*) from linkman"; //查询总记录数,对于这种聚合查询(查总数、最大值、平均值、最小值...)得到的都是一个数字回来 //一般就是用ScalarHandler来处理结果 ,这种聚合查询回来的是一个long类型。 long result = (long) runner.query(sql , new ScalarHandler()); return (int) result; } /** * 查询当前某一页的集合数据 * @param currentPage 具体第几页 * @param pageSize 每页显示多少条 * @return 返回这一页集合数据List<LinkMan> */ public List<LinkMan> findByPage(int currentPage , int pageSize) throws SQLException { QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource()); //定义sql语句,要注意这里是分页查询记录的语句,所以limit关键字肯定少不了 String sql = "select * from linkman limit ? , ? "; // 参数一: sql语句,参数二: 结果集的处理器 //参数三: 忽略|跳过前面的多少条记录,参数四:每页显示多少条记录 return runner.query(sql , new BeanListHandler<LinkMan>(LinkMan.class) ,(currentPage - 1) * pageSize, pageSize); }
前端JSP页面
herf 属性中调用js函数的方法 href="javascript:方法名(EL表达式)"
<h3 style="text-align: center">显示所有联系人</h3> <table border="1" class="table table-bordered table-hover"> <tr class="success"> <th>编号</th> <th>姓名</th> <th>性别</th> <th>年龄</th> </tr> <c:forEach items="${list}" var="linkMan" varStatus="i"> <tr> <td>${i.count}</td> <td>${linkMan.name}</td> <td>${linkMan.sex}</td> <td>${linkMan.age}</td> <td><a class="btn btn-default btn-sm" href="修改联系人.html">修改</a> <%-- herf 属性中调用js函数的方法 href="javascript:方法名(EL表达式)" <a class="btn btn-default btn-sm" href="linkManServlet?method=delete&id=${linkMan.id}">删除</a> --%> <a class="btn btn-default btn-sm" href="javascript:del(${linkMan.id})">删除</a> </td> </tr> </c:forEach> <tr> <td colspan="8" align="center"> <a class="btn btn-primary" href="${pageContext.request.contextPath }/add.jsp">添加联系人</a></td> </tr> </table> <script> function del(id) { if (confirm("确定要删除吗?")) { location.href = "linkManServlet?method=delete&id=" + id; } } </script> <% ------------------- %> <h3>添加联系人页面</h3> <form action="linkManServlet?method=add" method="post"> <div class="form-group"> <label for="name">姓名:</label> <input type="text" class="form-control" id="name" name="name" placeholder="请输入姓名"> </div> <div class="form-group"> <label>性别:</label> <input type="radio" name="sex" value="男" checked="checked"/>男 <input type="radio" name="sex" value="女"/>女 </div> <div class="form-group"> <label for="age">年龄:</label> <input type="text" class="form-control" id="age" name="age" placeholder="请输入年龄"> </div> <div class="form-group" style="text-align: center"> <input class="btn btn-primary" type="submit" value="提交" /> <input class="btn btn-default" type="reset" value="重置" /> <input class="btn btn-default" type="button" value="返回" /> </div> </form> <% ------------------- %> <h3 style="text-align: center">分页所有联系人</h3> <table border="1" class="table table-bordered table-hover"> <tr class="success"> <th>编号</th> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>操作</th> </tr> <c:forEach items="${pageBean.list}" var="linkMan" varStatus="i"> <tr> <td>${i.count}</td> <td>${linkMan.name}</td> <td>${linkMan.sex}</td> <td>${linkMan.age}</td> <td><a class="btn btn-default btn-sm" href="修改联系人.html">修改</a> <a class="btn btn-default btn-sm" href="linkManServlet?method=delete&id=${linkMan.id}">删除</a></td> </tr> </c:forEach> <tr> <td colspan="8" align="center"> <ul class="pagination success"> <%--如果现在的当前页是第一页,那么禁止点击 << 回到前一页--%> <c:if test="${pageBean.currentPage == 1}"> <li class="disabled"><a href="#" aria-label="Previous"> <span aria-hidden="true">«</span></a></li> </c:if> <%-- 如果现在的当前页不是第一页,那么可以点击 << 回到前一页--%> <c:if test="${pageBean.currentPage != 1}"> <li> <a href="linkManServlet?method=findByPage¤tPage=${pageBean.currentPage-1}&pageSize=${pageBean.pageSize}" aria-label="Previous"><span aria-hidden="true">«</span></a></li> </c:if> <c:forEach begin="1" end="${pageBean.totalPage}" var="i"> <%--这里的页码也有特殊的地方,如果这个页码正好是当前页,那么给他来一点背景色--%> <c:if test="${pageBean.currentPage == i}"> <li class="active"><a href="#">${i}</a></li> </c:if> <%--如果这个页码不是当前页,那么就是一种普通的<li>标签就行--%> <c:if test="${pageBean.currentPage != i}"> <%--这里还要考虑点击页码,请求这一页的数据回来的情况。--%> <li> <a href="linkManServlet?method=findByPage¤tPage=${i}&pageSize=${pageBean.pageSize}">${i}</a> </li> </c:if> </c:forEach> <%--如果现在的当前页已经是最后一页了,那么禁止点击 >> --%> <c:if test="${pageBean.currentPage == pageBean.totalPage}"> <li class="disabled"><a href="#" aria-label="Next"><span aria-hidden="true">»</span></a> </li> </c:if> <%--如果现在的当前页不是最后一页,那么可以点击 >> 去下一页。 --%> <c:if test="${pageBean.currentPage != pageBean.totalPage}"> <li> <a href="linkManServlet?method=findByPage¤tPage=${pageBean.currentPage+1}&pageSize=${pageBean.pageSize}" aria-label="Next"><span aria-hidden="true">»</span></a></li> </c:if> <li><a href="#" aria-label="Next"><span aria-hidden="true">»</span></a></li> </ul> </td> </tr> </table>