Web阶段(day14 filter&listener)

1.Filter 过滤器
    1.1 filter是Servlet三大技术之一。(servlet、filter、listener)
        在请求或响应操作完成之后,要对其进行放行操作,在放行前后可以执行额外操作。
    1.2 filter作用
        全站乱码过滤
        30天自动登录
    1.3 filter
        1.3.1 filter生命周期
            当web应用被加载时,filter会创建一个对象,保留在tomcat内存当中,并且调用init方法进行初始化,如果请求被过滤器拦截,则一定会调用doFilter()方法,在方法内实现请求响应的处理。处理过后可以对request和response选择放行或不放行。如果放行,在放行前后还可以执行额外的操作。在web应用被移出容器的时候filter对象会随之销毁,并且在销毁之前会调用destroy()方法执行善后的操作。
        1.3.2 责任链模式
            在一个网站中可能会有多个过滤器,所有的请求必须通过全部的过滤器才可以访问到对应的资源。这些过滤器连在一起,组成了一个过滤器的链,这个链称之为责任链模式。filter执行顺序是通过filter-mapping标签进行配置。在web.xml配置文件中,写在前边的filter优先加载。
        1.3.4 修改EasyMall项目
            思路:现在EasyMall项目中新建一个包,包名为com.easymall.filter,在包中新建一个普通类,实现Filter接口(javax.servlet下的)。然后再web.xml中添加filter配置。(filter中添加filter-name和filter-class,filter-mapping中添加filter-name和url-pattern)。
        过滤器一:全站乱码过滤
        a. 乱码处理中,响应乱码处理,只需一句话:response.setContentType("text/html;charset=utf-8");
        b. 如果是post请求,则只需一句:
            request.setCharacterEncoding("utf-8");即可。
        c. 如果是get请求,则需要单独对每一个请求参数进行处理。
        d. 单独处理每一个请求的中的乱码十分繁琐,所以应该在过滤器中重写获取参数时的方法。
        重写的方法有:(涉及到获取参数的都需要修改)
            getParameter()
            getParameterValues()
            getParameterMap()
        重写方式:
            i. 继承。不可取,修改的是继承后的getParameter方法,原有request对象身上的乱码没有修改。
            ii. 装饰者模式。可以。装饰者模式可以通过一个入口对象修改其身上不满意的方法,这种方式修改的是原有request对象身上的方法实现。
            iii. 动态代理。可以。
        代码实现:
            i.乱码过滤器
             创建过滤器EncodingFilter:
            public class EncodingFilter implements Filter {
                boolean encode_use = true;
                String encode = "";
                public void init(FilterConfig filterConfig) throws ServletException {
                        //过滤器使用get提交,乱码过滤的开关
                        boolean encode_use = Boolean.parseBoolean(filterConfig.getServletContext().getInitParameter("encode_use"));
                        //获取web.xml中的字符集
                        String encode = filterConfig.getServletContext().getInitParameter("encode");
                        this.encode_use = encode_use;
                        this.encode = encode;
                }
                public void doFilter(ServletRequest request, ServletResponse response,
                    FilterChain chain) throws IOException, ServletException {
                    //get 请求
                    MyHttpServletRequest myrequest = (MyHttpServletRequest) (encode_use?new MyHttpServletRequest((HttpServletRequest)request,encode):request);
                    //post请求
                    //request.setCharacterEncoding("utf-8");
                    //响应
                    response.setContentType("text/html;charset="+encode);
                    //放行
                    chain.doFilter(myrequest, response);
                    }    
                public void destroy() {}
            }
            乱码处理类:MyHttpServletRequest
            public class MyHttpServletRequest extends  HttpServletRequestWrapper{
                HttpServletRequest request = null;
                String encode = "";
                public MyHttpServletRequest(HttpServletRequest request,String encode) {
                    super(request);
                    this.request= request;
                    this.encode = encode;
                }
                @Override
                public Map<String,String[]> getParameterMap() {
                    //取出原有map中的乱码处理
                    Map<String,String[]> map = request.getParameterMap();//包含乱码的map
                    //处理完成放入一个新的map中
                    Map<String,String[]> rmap = new HashMap<String,String[]>();
                    //乱码处理
                    try {
                        for(Map.Entry<String, String[]> entry:map.entrySet()){
                            String key = entry.getKey();
                            String[] values = entry.getValue();
                            //创建新数组,保存没有乱码的数据
                            String[] rvalues = new String[values.length];
                            //遍历处理每一个值的乱码
                            for(int i=0;i<values.length;i++){
                                    rvalues[i] = new String(values[i].getBytes("iso8859-1"),encode);
                            }
                            //将处理后的数组添加到新map中
                            rmap.put(key, rvalues);
                        }
                        //并将新的的map返回
                        return rmap;
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                        throw new RuntimeException();
                    }
                }
                @Override
                public String[] getParameterValues(String name) {
                    //在不包含乱码的新map中,每一个键都存有一个数组。
                    //当前方法就是希望通过键获取对应的数组。
                    //所以获取新map,根据键名,获取值(数组)
                    Map<String,String[]> map = getParameterMap();
                    //键名来自参数列表,由用户传入
                    return map.get(name);
                }
                @Override     
                public String getParameter(String name) {
                    //getParameterValues就是获取一个参数数组,
                    //取出数组中的第一个元素,即为getParameter所需数据。
                    String[] value = getParameterValues(name);
                    return value==null?null:value[0];
                }
            }
            添加配置信息:
            <!-- 乱码处理的开关,如果tomcat默认字符集已经是utf-8则此处设置为false -->
            <context-param>
                <param-name>encode_use</param-name>
                <param-value>true</param-value>
            </context-param>
            <!-- 控制过滤器使用何种编码的配置 -->
            <context-param>
                  <param-name>encode</param-name>
                  <param-value>utf-8</param-value>
            </context-param>
            <!-- 全站乱码过滤 -->
            <filter>
                  <filter-name>EncodingFilter</filter-name>
                  <filter-class>com.easymall.filter.EncodingFilter</filter-class>
            </filter>
            <filter-mapping>
                  <filter-name>EncodingFilter</filter-name>
                  <url-pattern>/*</url-pattern>
            </filter-mapping>
            ii.实现30天自动登录
            思路:1.由于用户信息需要保存30天,所以这些信息存放在cookie中。(涉及到密码可以使用MD5加密解决)
                  2.如果用户是未登陆状态则实现自动登录。
                  3.如果用户是未登录状态,并且包含自动登录cookie,其中的用户名和密码都是正确的,则自动登录。
                  4.如果用户名或密码错误,不作出任何提示。
                  5.不论能否登录都需要放行。
            代码实现:
            i. 创建LoginFilter
                //30天自动登录的过滤器
                public class LoginFilter implements Filter {
                    public void init(FilterConfig filterConfig) throws ServletException {  }
                    public void doFilter(ServletRequest request, ServletResponse response,
                        FilterChain chain) throws IOException, ServletException {
                        //操作UserService中的方法,所以准备对象
                        UserService userService = new UserService();
                        //将ServletRequest强转为HttpServletRequest,其中包含session获取的方法
                        HttpServletRequest req = (HttpServletRequest) request;
                        //1.用户是否登录
                        if(req.getSession(false)==null || req.getSession().getAttribute("user")==null){
                            //用户没有登录,则需要完成自动登录
                            //尝试获取自动登录cookie  autologin
                            Cookie autologinC = null;
                            Cookie[] cookies= req.getCookies();
                            if(cookies!=null){
                                    for(Cookie c:cookies){
                                            if("autologin".equals(c.getName())){
                                                    autologinC = c;
                                            }
                                    }
                            }
                            if(autologinC != null){
                                    String value = autologinC.getValue();//username#password
                                    String[] result = value.split("#");
                                    String username = URLDecoder.decode(result[0], "utf-8");
                                    String password = result[1];
                                    //可以直接调用userService中已经实现的loginUser方法实现登录
                                    User user = userService.loginUser(username, password);
                                    //添加到session域保存登录状态
                                    req.getSession().setAttribute("user", user);
                            }
                        }
                    //能否登录都要放行
                    chain.doFilter(request, response);
                    }
                    public void destroy() { }
                }
            ii. 配置web.xml文件
                <!-- 30天自动登录 -->
                <filter>
                    <filter-name>LoginFilter</filter-name>
                    <filter-class>com.easymall.filter.LoginFilter</filter-class>
                </filter>
                <filter-mapping>
                    <filter-name>LoginFilter</filter-name>
                    <url-pattern>/*</url-pattern>
                </filter-mapping>
            修改LoginServlet
                //2.获取请求参数
                String username = request.getParameter("username");
                String password = request.getParameter("password");
                String remname = request.getParameter("remname");
                String autologin = request.getParameter("autologin");
                
                //记住用户名--cookie实现
                if("true".equals(remname)){
                        Cookie cookie = new Cookie("remname",URLEncoder.encode(username, "utf-8"));
                        cookie.setPath(request.getContextPath()+"/");
                        cookie.setMaxAge(60*60*24*30);
                        response.addCookie(cookie);
                }else{
                        Cookie cookie = new Cookie("remname","");
                        cookie.setPath(request.getContextPath()+"/");
                        cookie.setMaxAge(0);
                        response.addCookie(cookie);
                }
                //判断是否选择30天自动登录
                //如果选中则创建一个30自动登录cookie
                if("true".equals(autologin)){              
                        Cookie cookie = new Cookie("autologin",URLEncoder.encode(username, "utf-8")+"#"+password);
                        cookie.setPath(request.getContextPath()+"/");
                        cookie.setMaxAge(60*60*24*30);
                        response.addCookie(cookie);
                }
            修改LogOutServlet
                //注销servlet
                public class LogOutServlet extends HttpServlet {
                        public void doGet(HttpServletRequest request, HttpServletResponse response)
                                throws ServletException, IOException {
                                if(request.getSession(false)!=null){
                                        //释放session,完成注销
                                        request.getSession(false).invalidate();
                                        //释放cookie,清空30天自动登录
                                        Cookie cookie = new Cookie("autologin","");
                                        cookie.setPath(request.getContextPath()+"/");
                                        cookie.setMaxAge(0);
                                        response.addCookie(cookie);
                                }
                                response.sendRedirect(request.getContextPath());
                        }
                        public void doPost(HttpServletRequest request, HttpServletResponse response)
                                throws ServletException, IOException {
                                doGet(request, response);
                
                        }
                }

2.MD5加密
    加密方式:MD5 sha1 sha512
    数据摘要加密算法 数据指纹加密算法。
    特点:任何内容的数据,经过加密之后,都会形成一个128位的2进制数据,通常写成32位16进制数据。
          同一份数据经过MD5加密得到的结果一定是一致。(但是存在极端性。)
          经过MD5加密的结果,无法恢复成原有的内容。只能操作的(密文可以变成正文,但是需要较长时间才能计算出结果。)
    作用:数据加密,网盘快传。
    MD5实现:
        a.数据库中数据加密:update user set password=MD5(password);
        b. 用户注册信息加密
            导入MD5Utils中的内容:
                //MD5加密工具类
                public class MD5Utils {
                    /**
                     * 使用md5的算法进行加密
                     */
                    public static String md5(String plainText) {
                        byte[] secretBytes = null;
                        try {
                                secretBytes = MessageDigest.getInstance("md5").digest(
                                        plainText.getBytes());
                        } catch (NoSuchAlgorithmException e) {
                                throw new RuntimeException("没有md5这个算法!");
                        }
                        String md5code = new BigInteger(1, secretBytes).toString(16);
                        for (int i = 0; i < 32 - md5code.length(); i++) {
                                md5code = "0" + md5code;
                        }
                        return md5code;
                    }
                }
            修改loginServlet
                //*登录功能servlet
                public class LoginServlet extends HttpServlet {
                    public void doGet(HttpServletRequest request, HttpServletResponse response)
                        throws ServletException, IOException {
                        //1.处理乱码
                    //request.setCharacterEncoding("utf-8");
                    //2.获取请求参数
                    //判断是否选择30天自动登录
                    //如果选中则创建一个30自动登录cookie
                    if("true".equals(autologin)){              
                            Cookie cookie = new Cookie("autologin",URLEncoder.encode(username, "utf-8")+"#"+MD5Utils.md5(password));
                            cookie.setPath(request.getContextPath()+"/");
                            cookie.setMaxAge(60*60*24*30);
                            response.addCookie(cookie);
                    }
                    UserService userService = new UserService();
                    try {
                            User user = userService.loginUser(username,MD5Utils.md5(password));
                            //此处完成用户登录
                            request.getSession().setAttribute("user", user);
                    } 
                }
            修改RegistServlet
                import com.mchange.v2.c3p0.ComboPooledDataSource;
                //注册servlet
                public class RegistServlet extends HttpServlet {
                        public void doGet(HttpServletRequest request, HttpServletResponse response)
                                throws ServletException, IOException {
                                //1.请求参数乱码处理
                //        request.setCharacterEncoding("utf-8");
                        //1.响应参数乱码处理
                //        response.setContentType("text/html;charset=utf-8");
                        //2.获取请求参数
                        //为用户相关操作做处理的类
                        UserService userService = new UserService();
                        //为了传递数据方便,将数据封装在一个javabean中
                        User user = new User(0,username,MD5Utils.md5(password),nickname,email);
                }
        
3.监听器
    3.1监听器概述
        listender 是servlet三大技术之一
        一旦满足监听器的条件,就会触发对应的操作,执行监听器中的动作。


    3.2 Listener监听的分类
        JAVAEE开发中,监听器共有三类八种。
        a. 监听三大作用域创建和销毁的监听器
            ServletContextListener 
            HttpSessionListener
            ServletRequestListener 
        案例:
            public class MyServletContextListener implements ServletContextListener {
                    public void contextInitialized(ServletContextEvent sce) {
                            System.out.println("ServletContext被初始化了。。。"+sce.getServletContext());
                    }
                    public void contextDestroyed(ServletContextEvent sce) {
                            System.out.println("ServletContext要被销毁了。。。"+sce.getServletContext());
                    }
            }
            <listener>
                    <listener-class>cn.tedu.listener.MyServletContextListener</listener-class>
            </listener>
        b. 监听三大作用域中属性变化的监听器
            ServletContextAttributeListener
            HttpSessionAttributeListener 
            ServletRequestAttributeListener
        案例:
            public class MySCAtrrListener implements ServletContextAttributeListener {
                    public void attributeAdded(ServletContextAttributeEvent scab) {
                            System.out.println("属性被加入sc域"+scab.getName()+"~"+scab.getValue());
                    }
                    public void attributeRemoved(ServletContextAttributeEvent scab) {
                            System.out.println("属性被移除出sc域"+scab.getName()+"~"+scab.getValue());
                    }
                    public void attributeReplaced(ServletContextAttributeEvent scab) {
                            System.out.println("属性被替换在sc域"+scab.getName()+"~"+scab.getValue()+"~"+scab.getServletContext().getAttribute(scab.getName()));
                    }
            }
            <listener>
                    <listener-class>cn.tedu.listener.MySCAtrrListener</listener-class>
            </listener>
        c. 监听JavaBean在Session域中状态变化的监听器
            HttpSessionBindingListener
            HttpSessionActivationListener
            i. HttpSessionBindingListener
                让javabean自己感知到自己被存入或移除出session的状态变化的监听器
                此监听器不需要单独开发类,也不需要在web.xml中进行配置,而是直接让需要监听的JavaBean实现即可。
                其中具有两个方法:
                //当当前javabean的对象被存入session时触发
                public void valueBound(HttpSessionBindingEvent event) {
                }
                //当当前javabean的对象被移除出session时触发
                public void valueUnbound(HttpSessionBindingEvent event) {
                }
            ii. *了解*HttpSessionActivationListener
                让javabean自己感知到自己随着session被钝化和活化
    3.3 监听器案例
        开发监听器,记录应用启动关闭 记录资源被访问 记录用户登录注销 的日志
    
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值