• 退出(注销)
      在controller中清空session,覆盖cookie
      在2个过滤器中需要放过退出的请求
      * 页面注销时提示一个询问框
      ```java //LogoutController.java package com.duyi.qxgl07.controller;

    import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException;

    public class LogoutController extends HttpServlet { @Override //@Auto(“com.qxgl.login”) protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //清空登录成功时装载数据 //清空session req.getSession().removeAttribute(“loginUser”);

    1. //覆盖浏览器cookie(清空效果)
    2. Cookie c = new Cookie("tokenId","-1"); //由于返回值为-1,就是时间等于0,所以直接清空
    3. //让时效等于0 -- 当时间为0
    4. c.setMaxAge(0);
    5. resp.addCookie(c);
    6. resp.sendRedirect("/");
    7. }

    }

    1. * 角色概要设计 (建表,建实体)<br /> create table t_role(<br /> rid int primary key auto_increment, //自增<br /> rname varchar(16),<br /> rdescription varchar(32),<br /> yl1 varchar(16), //表示与角色的关联<br /> yl2 varchar(16)<br /> )<br /> <br /> * 思考: 用户和角色的关系 (一对一,一对多,多对多)<br /> 理论上应该是一对多关系<br /> 需要在user表整增加一个关联角色表的外键rid<br /> create table t_user(<br /> uid , <br /> ....<br /> rid (外键)<br /> )<br /> 由于user表已经创建并使用<br /> 为了不影响之前的操作<br /> 不建议修改user表<br /> 我们可以考虑新建一个用户和角色的中间表,存储用户和角色的关系<br /> <br /> create table t_user_role(<br /> uid int , <br /> rid int ,<br /> primary key(uid,rid)<br /> )<br />* 功能管理概要设计<br /> create table t_fun(<br /> fid int primary key auto_increment,<br /> fname varchar(16) , -- "权限管理" , "数据导入" ,"用户管理"<br /> ftype int, -- 功能类别 1菜单,2按钮<br /> fhref varchar(64), -- 菜单对应的请求 "" "findUser"<br /> fauth varchar(32), -- 权限标识 <br /> pid int, -- 当前功能所属的父级功能id , 根菜单的父级功能是-1<br /> yl1 varchar(16),<br /> yl2 varchar(16)<br /> )<br /> 1 权限管理 1 null com.qxgl -1<br /> 2 用户管理 1 "findUser" com.qxgl.user 1<br /> 3 用户新建 2 "" com.qxgl.user.add 2<br /> 4 用户删除 2 "" com.qxgl.user.del 2<br /> 5 角色管理 1 "findRole" com.qxgl.role 1<br /> ![image.png](https://cdn.nlark.com/yuque/0/2022/png/8409167/1642839604004-50d669cc-cad6-4d91-8d75-14cadef4587b.png#clientId=u46987cdd-ff0c-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=253&id=TXUir&margin=%5Bobject%20Object%5D&name=image.png&originHeight=505&originWidth=479&originalType=binary&ratio=1&rotation=0&showTitle=false&size=39898&status=done&style=none&taskId=u501ee601-96aa-4497-ad71-9951826b425&title=&width=239.5)
    2. * 通过分析,功能权限功能分为2种<br /> 1.功能菜单,主页面左侧统一展示<br /> * 由于不同的用户,可能会有不同的权限,会分配不同的功能菜单<br /> * 张三可能有10个菜单<br /> * 李四可能有5个菜单<br /> * 无论用户分配了几个权限菜单,最终展示的时候应该是通过循环展示的。<br /> * 因为每一个功能菜单都会有对应的功能请求<br /> * 这些请求应该是随着菜单循环展示的时候,被装入菜单选项。<br /> * 所以这个请求也需要像菜单名字一样,存储在数据库中
    3. 2.功能按钮,分散在不同的网页中,现在不同位置<br /> * 与菜单不同,按钮是不需要对应请求<br /> * 按钮显示的位置不确定<br /> * 所以需要在页面设计的时候,根据需求自定义按钮位置<br /> * 点击按钮发送的功能请求也是自定义按钮时匹配,不需要存储在数据库中<br /> * 权限标识属性<br /> * 不同的用户具有不同的权限<br /> * 在浏览器展示的效果就是不同的用户可以看到不同的菜单,可以看到不同的按钮<br /> * 无论看到哪些菜单和按钮,最终使用通过菜单和按钮完成背后的请求操作<br /> * 菜单或按钮背后的请求我们可以通过浏览器url直接发送<br /> * 所有当前用户是否具有当前url请求的权限,不能仅关注浏览器是否展示了对应的菜单和按钮<br /> * 还需要在服务端判断是否具有该请求的权限<br /> * 为每一个功能请求分配一个权限码 :com.qxgl.user.add<br /> * 用户具有该权限,就可以完成该权限码对应的请求<br /> * 该权限码对应哪些请求,可以使用注解配置在请求的方法上<br /> dmc用户 具有用户管理权限 权限码是com.qxgl.user<br /> <br /> class UserAddServlet{<br />//自定义注解,具有指定权限码的用户才能完成当前请求 userAdd<br /> @Auth("com.qxgl.user")<br /> service(){}<br /> }<br /> <br /> class UserDeleteServlet{<br /> @Auto("com.qxgl.user)<br /> serivce(){}<br /> }<br /> <br /> class UserEditServlet{<br /> @Auto("com.qxgl.user.edit")<br /> serivce(){}<br /> }
    4. //验证权限需要过滤器
    5. ```java
    6. //AuthFilter.java
    7. package com.duyi.qxgl.util;
    8. import javax.servlet.FilterChain;
    9. import javax.servlet.ServletException;
    10. import javax.servlet.http.HttpFilter;
    11. import javax.servlet.http.HttpServletRequest;
    12. import javax.servlet.http.HttpServletResponse;
    13. import java.io.IOException;
    14. public class AuthFilter extends HttpFilter {
    15. @Override
    16. protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
    17. //每次请求调用对应的servlet方法之前,需要判断一下当前用户具有的权限码和要访问的servlet方法上注解表示的权限码是否匹配
    18. //从数据库中获得当前用户具有的权限->权限码
    19. //通过过滤器获得servlet方法上注解->权限码
    20. // 过滤器的使用体现AOP->责任链模式->有一个链对象chain->链中包含了要执行的所有切面filter和最终目标servlet
    21. //2个权限码比较
    22. //chain是一个接口,将他变为一个实现类
    23. }
    24. }
    • 登录时验证码刷新
      * 点击验证码,更换/刷新验证码
      1. //reloadCode.js -- web
      2. var no=1; //设置一个全局变量
      3. function reloadCode(){
      4. //改换验证码,<img src="2.jpg">重新设置src属性
      5. //找到这个标签
      6. var img = document.getElementById('codeImg'); //验证码的图片
      7. //重新发送一次验证码的请求 -- 需要让每一次的请求参数发生变化
      8. //让服务器认为不是同一次请求
      9. img.src='generatcheckcode?no='+no++;
      10. }

    权限关系:
    用户
    1 dmc 123
    2 zzt 123
    角色
    11 vip1
    22 vip2
    功能
    1 权限管理 1 null com.qxgl -1
    2 用户管理 1 “findUser” com.qxgl.user 1
    3 用户新建 2 “” com.qxgl.user.add 2
    4 用户删除 2 “” com.qxgl.user.del 2
    5 角色管理 1 “findRole” com.qxgl.role 1
    用户角色
    1 , 11
    角色功能
    11,1
    11,2
    11,3

    1. //LoginView.java
    2. package com.duyi.qxgl.view;
    3. import javax.servlet.ServletException;
    4. import javax.servlet.http.HttpServlet;
    5. import javax.servlet.http.HttpServletRequest;
    6. import javax.servlet.http.HttpServletResponse;
    7. import java.io.IOException;
    8. //是一个用来动态拼装登录页面的servlet
    9. public class LoginView extends HttpServlet {
    10. /*
    11. 一般4开头的都代表没找到
    12. 405 : 表示处理请求的方法没有找到
    13. service可以处理get和post请求
    14. doGet可以处理get请求
    15. doPost可以处理post请求
    16. */
    17. @Override
    18. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    19. //拼页面
    20. String f = req.getParameter("f");
    21. //服务器响应时使用utf-8处理
    22. resp.setCharacterEncoding("utf-8");
    23. StringBuilder html = new StringBuilder();
    24. html.append("<html>");
    25. html.append(" <head>");
    26. html.append(" <title>登录222</title>");
    27. //告诉浏览器显示时按照 utf-8处理
    28. html.append(" <meta charset=\"utf-8\"/>");
    29. html.append(" <link rel=\"stylesheet\" type=\"text/css\" href=\"layui/css/layui.css\" />");
    30. html.append(" <script src=\"layui/layui.all.js\"></script>");
    31. html.append(" <style>");
    32. html.append(" body{");
    33. html.append(" width:100%;");
    34. html.append(" height:100%;");
    35. html.append(" background-image: url(imgs/img.png);");
    36. html.append(" background-repeat: repeat-x;");
    37. html.append(" background-size: 100% 100%;");
    38. html.append(" }");
    39. html.append(" .layui-card{");
    40. html.append(" width:350px;");
    41. html.append(" margin:100px auto ;");
    42. html.append(" opacity: 0.8;");
    43. html.append(" }");
    44. html.append(" tr{");
    45. html.append(" height:50px;");
    46. html.append(" }");
    47. html.append(" </style>");
    48. html.append(" <script>");
    49. //需要判断,在显示
    50. if(f != null && "9".equals(f)){
    51. html.append("alert('用户名密码错误');");
    52. }
    53. if(f != null && "8".equals(f)){
    54. html.append("alert('验证码为空或不正确');");
    55. }
    56. html.append(" </script>");
    57. html.append(" </head>");
    58. html.append(" <body>");
    59. html.append(" <div class=\"layui-card\">");
    60. html.append(" <div class=\"layui-card-header\">用户登录</div>");
    61. html.append(" <div class=\"layui-card-body\">");
    62. html.append(" <form action=\"login\" method=\"post\">");
    63. html.append(" <table>");
    64. html.append(" <tr>");
    65. html.append(" <td>用户名:</td>");
    66. html.append(" <td>");
    67. html.append(" <input type=\"text\" name=\"uname\" required lay-verify=\"required\" class=\"layui-input\">");
    68. html.append(" </td>");
    69. html.append(" </tr>");
    70. html.append(" <tr>");
    71. html.append(" <td>密码:</td>");
    72. html.append(" <td><input type=\"password\" name=\"upass\" class=\"layui-input\" /></td>");
    73. html.append(" </tr>");
    74. html.append(" <tr>");
    75. html.append(" <td colspan='2'><input style='width:100px;height:30px;' type=\"text\" name=\"code\" class=\"layui-input-inline\"/><img id='codeImg' src='generatcheckcode' onclick='reloadCode()' /></td>");
    76. html.append(" </tr>");
    77. html.append(" <tr>");
    78. html.append(" <td colspan='2'><input type=\"checkbox\" name=\"autoflag\" /> 1周内自动登录</td>");
    79. html.append(" </tr>");
    80. html.append(" <tr>");
    81. html.append(" <td> <button>登录</button> </td>");
    82. html.append(" </tr>");
    83. html.append(" </table>");
    84. html.append(" </form>");
    85. html.append(" </div>");
    86. html.append(" </div>");
    87. html.append(" </body>");
    88. html.append(" <script src='js/reloadcode.js'></script>");
    89. html.append("</html>");
    90. //将网页直接响应回去
    91. resp.getWriter().write(html.toString());
    92. /*
    93. servlet 和 jsp都可以拼装动态网页
    94. servlet = java(主场) + html
    95. jsp = java + html(主场)
    96. */
    97. }
    98. }