1. 全站乱码过滤
在整个EasyMall项目中,有多处都需要进行乱码处理,这些内容可以提取到一个模块中,这个模块可以是一个过滤器。
过滤器需要将请求与响应中的乱码进行处理。
a. 处理方式:
i. 响应乱码
response.setContentType("text/html;charset=utf-8");
ii. 请求乱码
分get与post两种情况。
如果为post请求,则只需:request.setCharacterEncoding("utf-8");
如果为get请求,则需要将每一个参数的乱码进行处理。
并且如果将参数取出之后再进行处理,那么下一个request 的参数还需要再次处理,也不能确定需要处理的参数都有哪些,所以应该将原有request对象身上的参数处理完成,再设置回原有request身上才行。
iii. 解决方案:
1) 继承:可以重写方法但是不是修改的原有类中的方法,不符合需求。
2) 装饰者模式:是修改原有类中的方法,满足需求。
3) 动态代理:自行了解。
装饰类就是我们写的,通过装饰类的构造函数来接收装饰类的对象
b. 代码实现:
创建EncodingFilter.java
package com.easymall.filter; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; public class EncodingFilter implements Filter { String encode = null; boolean use_encode ; public void init(FilterConfig filterConfig) throws ServletException { //在当前过滤器配置信息对象的身上, //可以引入代表web应用的对象servletContext,这样即可获取全局配置信息 encode = filterConfig.getServletContext().getInitParameter("encode"); //读取字符集是否使用的开发 use_encode = Boolean.parseBoolean(filterConfig.getServletContext().getInitParameter("use_encode")); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //1.请求乱码处理post // request.setCharacterEncoding("utf-8"); //get请求乱码处理 HttpServletRequest req = (HttpServletRequest) (use_encode?//use_encode是是否使用编码的开关,如果为true就说明tomcat配置的编码格式和我要求的不一样是iso8859-1我要用全站乱//码解析,如果不为true就代表tomcat的编码格式配置好了 utf-8不需要再做修改所以是正常的request 而不是装饰者的request
new MyHttpServletRequest((HttpServletRequest) request,encode):request); //红色返回的是HTTPservletrequestWRAP的对象 可以用
HTTPservletrequest接住
//2.响应乱码 response.setContentType("text/html;charset="+encode); //放行 chain.doFilter(req, response); } public void destroy() { } }
添加web.xml配置
<!-- 全站乱码过滤器 --> <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>
创建MyHttpServletRequest类
package com.easymall.filter; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; public class MyHttpServletRequest extends HttpServletRequestWrapper{ //本来实现的是HttpServletRequest接口,但是其要实现的方法太多了,我们只要实现获取参数的方法,更改参数中的乱码就行,所以我们采用HttpServletResquestWapper 他是HttpServletRequestWrapper 子实现抽象接口 HttpServletRequest request = null; String encode = null; public MyHttpServletRequest(HttpServletRequest request,String encode) { super(request); this.request = request; this.encode = encode; } @Override public Map<String,String[]> getParameterMap() { //将原有map中的参数取出,处理乱码之后放入新的map中,并且返回新map Map<String,String[]> map = request.getParameterMap(); //取出原map中的参数名和参数值,将处理后的参数值放入新map Map<String,String[]> rmap = new HashMap(); //遍历原map,处理参数值乱码 try { for(Map.Entry<String, String[]> entry:map.entrySet()){ String key = entry.getKey();//获取键名备用 String[] value = entry.getValue();//需要处理乱码 //遍历数组,将每一个值做乱码处理,再将乱码处理后的数据放入一个新的数组中。 String[] rvalue = new String[value.length];//创建一个与原数组长度相同的数组,来存储处理后的数据 for(int i=0;i<value.length;i++){//遍历数组中每一个元素 //处理数组中每一个元素的乱码,并放入新数组中 rvalue[i] = new String(value[i].getBytes("iso8859-1"),encode); } //将新数组添加到新map中 rmap.put(key, rvalue); } return rmap; } catch (Exception e) { throw new RuntimeException(e); } } @Override public String[] getParameterValues(String name) { //获取乱码处理后的getParameterMap方法中的值,即当前方法所需结果 Map<String,String[]> map = getParameterMap(); return map.get(name); } @Override public String getParameter(String name) { //上方方法的返回值是一个数组,取出数组中的第一个元素即可 String[] values = getParameterValues(name); return values!=null?values[0] : null; } }
iv. 添加全局配置信息 <!-- 字符集选择 --> <context-param> <param-name>encode</param-name> <param-value>utf-8</param-value> </context-param> <!-- 字符集使用开关 --> <context-param> <param-name>use_encode</param-name> <param-value>true</param-value> </context-param>
二.30天自动登录
在EasyMall的登录页面,可以选择30天内容自动登录。
用户信息需要保存30天,使用session不合适,应该考虑将用户信息存入cookie中。
由于整个网站的页面可能都会需要登录状态,所以可以将全部页面过滤,判断是否需要自动登录,过滤器可以满足需求。
代码实现:
创建loginFilter
package com.easymall.filter; import java.io.IOException; import java.net.URLDecoder; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import com.easymall.domain.User; import com.easymall.exception.MsgException; import com.easymall.service.UserService; public class LoginFilter implements Filter { UserService userService = new UserService(); public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request;//ServletRequest接口无法获得getCookie这个方法所以采用了他的子级接口HttpServletRequest来做强转 //读取cookie用户信息autologin //1.获取全部cookie Cookie[] cs = req.getCookies(); //获取到请求体中的cooies //2.遍历cookie,从中寻找autologin,自动登录cookie Cookie autologinC = null; if(cs != null){ for(Cookie c:cs){ if("autologin".equals(c.getName())){ autologinC = c; } } } //找到了autologin,取出用户名和密码,与数据库中的数据比对 if(autologinC != null){ //取出用户名密码 String value = URLDecoder.decode(autologinC.getValue(), "utf-8"); //value的组成应该为username+#+password,所以根据#切割 String[] vs = value.split("#"); String username = vs[0]; String password = vs[1]; try { //与数据库中的数据比对 //由于在三层框架中userService服务层已经实现了登录功能,所以此处直接调用即可。 User user = userService.loginUser(username, password); //保存登录状态--添加到session域 req.getSession().setAttribute("user", user); } catch (MsgException e) { throw new RuntimeException(e); } } //放行 chain.doFilter(req, response); } public void destroy() { } }
修改loginservlet
package com.easymall.web; import java.io.IOException; import java.net.URLEncoder; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; 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 javax.servlet.http.HttpSession; import com.easymall.domain.User; import com.easymall.service.UserService; import com.easymall.utils.JDBCUtils; import com.easymall.utils.MD5Utils; public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //乱码处理 // request.setCharacterEncoding("utf-8"); //response.setContentType("text/html;charset=utf-8"); //1.获取参数 String username=request.getParameter("username"); String password=request.getParameter("password"); String remname=request.getParameter("remname"); //"true" String autologin=request.getParameter("autologin"); //2.记住用户名---cookie //remname 为"true"则表示要记住用户名。,反之为null 不需要记住用户名 if("true".equals(remname)){ Cookie cookie=new Cookie("remname",URLEncoder.encode(username,"utf-8") ); cookie.setMaxAge(60*60*24*30);//30天记住用户名 cookie.setPath(request.getContextPath()+"/"); response.addCookie(cookie); } else { Cookie cookie=new Cookie("remname", ""); cookie.setMaxAge(0);//删除cookie所以设置时间为0 cookie.setPath(request.getContextPath()+"/"); response.addCookie(cookie); } //判断是否需要自动登录,如果需要则创建一个自动登录的cookie,保存用户信息30天 if("true".equals(autologin)) { Cookie cookie=new Cookie("autologin", URLEncoder.encode(username+"#"+MD5Utils.md5(password), "UTF-8")); cookie.setMaxAge(60*60*24*30); cookie.setPath(request.getContextPath()+"/"); response.addCookie(cookie); } //3.保存用户登录状态 ---session //判断用户名和密码是否匹配 /* Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try { conn=JDBCUtils.getConnection(); ps=conn.prepareStatement("select * from user where username=? and password=?"); ps.setString(1, username); ps.setString(2, password); rs=ps.executeQuery(); if(rs.next()){//用户名和密码正确,完成登录 HttpSession session=request.getSession(); session.setAttribute("username", username); } else { //返回登录页面做出提示 request.setAttribute("msg", "用户名或密码不正确"); request.getRequestDispatcher("/_login.jsp").forward(request, response); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ JDBCUtils.close(conn, ps, rs); }*/ //传输数据到UserService UserService userService=new UserService(); try { User user=userService.loginUser(username,MD5Utils.md5(password)); //因为需要登录成功后保存登录状态,那么返回值是查找到的user对象 //得到user对象,放入session域 保持登录状态 request.getSession().setAttribute("user", user); } catch (Exception e) { request.setAttribute("msg", e.getMessage()); request.getRequestDispatcher("/_login.jsp").forward(request, response); return; } //4.跳转会首页 response.sendRedirect(request.getContextPath()+"/");//跳转到不同服务器要加上域名 ,同一个服务器指定web应用 } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
修改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>