一、解决全站字符乱码(post和get中文编码问题)
乱码问题:
- 获取请求参数中的乱码问题;
- POST请求:request.setCharacterEncoding(“utf-8”);
- GET请求:new String(request.getParameter(“xxx”).getBytes(“iso-8859-1”), “utf-8”);
- 响应的乱码问题:
- response.setContextType(“text/html;charset=utf-8”)
使用Decorator模式包装request对象解决get和post请求方式下的中文乱码问题
编写一个用于处理中文乱码的过滤器CharacterEncodingFilter,代码如下:
1 package cn.zy.filter; 2 3 import java.io.IOException; 4 import javax.servlet.Filter; 5 import javax.servlet.FilterChain; 6 import javax.servlet.FilterConfig; 7 import javax.servlet.ServletException; 8 import javax.servlet.ServletRequest; 9 import javax.servlet.ServletResponse; 10 import javax.servlet.http.HttpServletRequest; 11 import javax.servlet.http.HttpServletRequestWrapper; 12 import javax.servlet.http.HttpServletResponse; 13 14 public class CharacterEncodingFilter implements Filter { 15 private FilterConfig filterConfig = null; 16 //设置默认的字符编码 17 private String defaultCharset = "UTF-8"; 18 19 public void doFilter(ServletRequest req, ServletResponse resp, 20 FilterChain chain) throws IOException, ServletException { 21 HttpServletRequest request = (HttpServletRequest)req; 22 HttpServletResponse response = (HttpServletResponse) resp; 23 //得到在web.xml中配置的字符编码 24 String charset = filterConfig.getInitParameter("charset"); 25 if(charset==null){ 26 charset = defaultCharset; 27 } 28 request.setCharacterEncoding(charset); 29 response.setCharacterEncoding(charset); 30 response.setContentType("text/html;charset="+charset); 31 32 //使用得到加强的request 33 EncodingRequest requestWrapper = new EncodingRequest(request); 34 chain.doFilter(requestWrapper, response); 35 } 36 37 public void init(FilterConfig filterConfig) throws ServletException { 38 this.filterConfig = filterConfig; 39 40 } 41 42 public void destroy() { 43 } 44 45 /* 46 * 写一个装饰类增强HttpServletRequest对象 47 */ 48 class EncodingRequest extends HttpServletRequestWrapper { 49 //定义一个变量记住被增强对象(request对象是需要被增强的对象) 50 private HttpServletRequest request; 51 //定义一个构造函数,接收被增强对象 52 public EncodingRequest(HttpServletRequest request) { 53 super(request); 54 this.request = request; 55 } 56 /* 覆盖需要增强的getParameter方法 57 * @see javax.servlet.ServletRequestWrapper#getParameter(java.lang.String) 58 */ 59 @Override 60 public String getParameter(String name) { 61 try{ 62 //获取参数的值 63 String value= this.request.getParameter(name); 64 if(value==null){ 65 return null; 66 } 67 //如果不是以get方式提交数据的,就直接返回获取到的值 68 if(!this.request.getMethod().equalsIgnoreCase("get")) { 69 return value; 70 }else{ 71 //如果是以get方式提交数据的,就对获取到的值进行转码处理 72 value = new String(value.getBytes("ISO8859-1"),this.request.getCharacterEncoding()); 73 return value; 74 } 75 }catch (Exception e) { 76 throw new RuntimeException(e); 77 } 78 } 79 } 80 }
在web.xml文件中配置Filter
<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>cn.zy.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>name</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
编写一个测试的用的jsp提交表单
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 <% 4 String path = request.getContextPath(); 5 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 6 %> 7 8 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 9 <html> 10 <head> 11 <base href="<%=basePath%>"> 12 13 <title>My JSP 'index.jsp' starting page</title> 14 <meta http-equiv="pragma" content="no-cache"> 15 <meta http-equiv="cache-control" content="no-cache"> 16 <meta http-equiv="expires" content="0"> 17 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 18 <meta http-equiv="description" content="This is my page"> 19 <!-- 20 <link rel="stylesheet" type="text/css" href="styles.css"> 21 --> 22 </head> 23 24 <body> 25 <form action="<c:url value='/Aservlet'/>" method="post"> 26 用户名: <input type="text" name="username"> 27 <input type="submit" value="提交"/> 28 </form> 29 <a href="<c:url value='/Aservlet?username=张三'/>">点击这里</a><br/> 30 </body> 31 </html>
编写一个Servlet用于处理请求
1 package cn.zy.filter; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 public class Aservlet extends HttpServlet { 12 13 /** 14 * The doGet method of the servlet. <br> 15 * 16 * This method is called when a form has its tag value method equals to get. 17 * 18 * @param request the request send by the client to the server 19 * @param response the response send by the server to the client 20 * @throws ServletException if an error occurred 21 * @throws IOException if an error occurred 22 */ 23 public void doGet(HttpServletRequest request, HttpServletResponse response) 24 throws ServletException, IOException { 25 String username = request.getParameter("username"); 26 //获取请求方式 27 String method = request.getMethod(); 28 response.getWriter().print("请求方式" +method+"参数:"+username); 29 } 30 31 32 public void doPost(HttpServletRequest request, HttpServletResponse response) 33 throws ServletException, IOException { 34 doGet(request, response); 35 } 36 37 }
二、统计每个访问次数
写一个监听器,在服务启动时创建一个map,用于保存访问IP和次数
1 package cn.zy.listener; 2 3 import java.util.LinkedHashMap; 4 import java.util.Map; 6 import javax.servlet.ServletContext; 7 import javax.servlet.ServletContextEvent; 8 import javax.servlet.ServletContextListener; 9 10 public class CreateMapListener implements ServletContextListener { 11 12 public void contextInitialized(ServletContextEvent sce) { 13 /* 14 * 在服务器启动时创建map 15 */ 16 Map<String,Integer> map = new LinkedHashMap<String,Integer>(); 17 //得到ServletContext 18 ServletContext application = sce.getServletContext(); 19 //把Map保存到ServletContext中 20 application.setAttribute("map", map); 21 } 22 23 public void contextDestroyed(ServletContextEvent sce) { 24 25 } 26 27 }
创建一个Filter用于统计访问次数
package cn.zy.filter; import java.io.IOException; import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /* * 获取某个IP访问本站的次数 */ public class AccessCountFilter implements Filter { private FilterConfig config; public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //1. 得到appliction ServletContext app = config.getServletContext(); //2.从application中获取map Map<String,Integer> map = (Map<String, Integer>) app.getAttribute("map"); //3.获取客户端的地址 String ip = request.getRemoteAddr(); /* * 4.进行判断IP是否是第一次访问,如果不是则加1,如果是则设置为1 */ if(map.containsKey(ip)){ int cnt = map.get(ip); map.put(ip, cnt+1); }else{ map.put(ip, 1); } //5.把map重新放回到app中 app.setAttribute("map", map); //6.放行 chain.doFilter(request, response); } public void init(FilterConfig filterConfig) throws ServletException { this.config=filterConfig; } }
web.xml中的配置:
<filter> <filter-name>AccessCountFilter</filter-name> <filter-class>cn.zy.filter.AccessCountFilter</filter-class> </filter> <filter-mapping> <filter-name>AccessCountFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置Listener --> <listener> <listener-class>cn.zy.listener.CreateMapListener</listener-class> </listener>
创建一个jsp用于显示
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 <% 4 String path = request.getContextPath(); 5 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 6 %> 7 8 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 9 <html> 10 <head> 11 <base href="<%=basePath%>"> 12 13 <title>My JSP 'show.jsp' starting page</title> 14 15 <meta http-equiv="pragma" content="no-cache"> 16 <meta http-equiv="cache-control" content="no-cache"> 17 <meta http-equiv="expires" content="0"> 18 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 19 <meta http-equiv="description" content="This is my page"> 20 <!-- 21 <link rel="stylesheet" type="text/css" href="styles.css"> 22 --> 23 24 </head> 25 26 <body> 27 <h1 align="center">显示结果</h1> 28 <table align="center" width="60%" border="1"> 29 <tr> 30 <th>IP</th> 31 <th>次数</th> 32 </tr> 33 <c:forEach items="${applicationScope.map }" var="entry"> 34 <tr> 35 <td>${entry.key }</td> 36 <td>${entry.value }</td> 37 </tr> 38 </c:forEach> 39 </table> 40 </body> 41 </html>
结果如下图所示:
三、粗粒度权限控制(控制页面的访问权限)
目的:
我们给出三个页面:index.jsp、user.jsp、admin.jsp。
l index.jsp:谁都可以访问,没有限制;
l user.jsp:只有登录用户才能访问;
l admin.jsp:只有管理员才能访问。
创建一个登陆界面,用于提交表单
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'login.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <h1>登录</h1> ${msg } <form action="<c:url value='/LoginServlet' />" method="post"> 用户名:<input type="text" name="username" /><br> 密码:<input type="password" name="password" /> <br> <input type="submit" value="提交"> </form> </body> </html>
2.创建一个Servlet处理表单
package cn.zy.web.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); /* * 1.获取用户名 * 2.如果含有admin则是管理员 * 3.如果不包含则为普通用户 */ String username = request.getParameter("username"); if(username.contains("admin")){ request.getSession().setAttribute("admin", username); }else{ request.getSession().setAttribute("username", username); } request.getRequestDispatcher("/index.jsp").forward(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }
2.创建一个jsp,用于链接到不同的页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <h1>你就是个游客而已</h1> <a href="<c:url value='/index.jsp'/>">游客入口</a><br/> <a href="<c:url value='/users/u.jsp'/>">会员入口</a><br/> <a href="<c:url value='/admin/a.jsp'/>">管理员入口</a><br/> </body> </html>
3.创建两个jsp,内容就是普通用户能访问的页面和管理员才能访问的页面
4.做两个过滤器,用于权限控制
AdminFilter
package cn.zy.filter; import java.io.IOException; 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 AdminFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //得到Session HttpServletRequest req = (HttpServletRequest)request; String name = (String)req.getSession().getAttribute("admin"); if(name != null){ chain.doFilter(request, response); }else{ req.setAttribute("msg", "您不是管理员!"); req.getRequestDispatcher("/login.jsp").forward(request, response); } } public void init(FilterConfig arg0) throws ServletException { } }
UserFilter
package cn.zy.filter; import java.io.IOException; 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 UserFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String name = (String)req.getSession().getAttribute("admin"); if(name != null) { chain.doFilter(request, response); return; } name = (String)req.getSession().getAttribute("username"); if(name != null){ chain.doFilter(request, response); }else{ req.setAttribute("msg", "您不是管理员也不是会员!"); req.getRequestDispatcher("/login.jsp").forward(request, response); } } public void destroy() { } }
web.xml中的配置
<filter> <display-name>UserFilter</display-name> <filter-name>UserFilter</filter-name> <filter-class>cn.zy.filter.UserFilter</filter-class> </filter> <filter-mapping> <filter-name>UserFilter</filter-name> <url-pattern>/users/*</url-pattern> </filter-mapping> <filter> <display-name>AdminFilter</display-name> <filter-name>AdminFilter</filter-name> <filter-class>cn.zy.filter.AdminFilter</filter-class> </filter> <filter-mapping> <filter-name>AdminFilter</filter-name> <url-pattern>/admin/*</url-pattern> </filter-mapping>
四、 response增强案例——缓存数据到内存
对于页面中很少更新的数据,例如商品分类,为避免每次都要从数据库查询分类数据,因此可把分类数据缓存在内存或文件中,以此来减轻数据库压力,提高系统响应速度。
编写缓存数据的过滤器,代码如下:
package cn.zy.filter; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; 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.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; public class WebResourceCachedFilter implements Filter { /** * @Field: map * 缓存Web资源的Map容器 */ private Map<String,byte[]> map = new HashMap<String,byte[]>(); public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; response.setCharacterEncoding("utf-8"); //1.得到用户请求的uri String uri = request.getRequestURI(); //2.看缓存中有没有uri对应的数据 byte b[] = map.get(uri); //3.如果缓存中有,直接拿缓存的数据打给浏览器,程序返回 if(b!=null){ //根据字节数组和指定的字符编码构建字符串 String webResourceHtmlStr = new String(b,response.getCharacterEncoding()); System.out.println(webResourceHtmlStr); response.getOutputStream().write(b); return; } //4.如果缓存没有,让目标资源执行,并捕获目标资源的输出 BufferResponse myresponse = new BufferResponse(response); chain.doFilter(request, myresponse); //获取缓冲流中的内容的字节数组 byte out[] = myresponse.getBuffer(); //5.把资源的数据以用户请求的uri为关键字保存到缓存中 map.put(uri, out); //6.把数据打给浏览器 response.getOutputStream().write(out); } public void destroy() { } class BufferResponse extends HttpServletResponseWrapper{ private ByteArrayOutputStream bout = new ByteArrayOutputStream(); //捕获输出的缓存 private PrintWriter pw; private HttpServletResponse response; public BufferResponse(HttpServletResponse response) { super(response); this.response = response; } @Override public ServletOutputStream getOutputStream() throws IOException { return new MyServletOutputStream(bout); } @Override public PrintWriter getWriter() throws IOException { pw = new PrintWriter(new OutputStreamWriter(bout,this.response.getCharacterEncoding())); return pw; } public byte[] getBuffer(){ try{ if(pw!=null){ pw.close(); } return bout.toByteArray(); }catch (Exception e) { throw new RuntimeException(e); } } } class MyServletOutputStream extends ServletOutputStream{ private ByteArrayOutputStream bout; public MyServletOutputStream(ByteArrayOutputStream bout){ //接收数据写到哪里 this.bout = bout; } @Override public void write(int b) throws IOException { bout.write(b); } } }
在web.xml中配置Web资源缓存过滤器
<filter> <description>Web资源缓存过滤器</description> <filter-name>WebResourceCachedFilter</filter-name> <filter-class>cn.zy.filter.WebResourceCachedFilter</filter-class> </filter> <filter-mapping> <filter-name>WebResourceCachedFilter</filter-name> <!-- 映射需要缓存输出的JSP页面,这几个页面都只是单纯作为输入UI,不会有太多的变化,因此可以缓存输出 --> <url-pattern>/login.jsp</url-pattern> <url-pattern>/test.jsp</url-pattern> <url-pattern>/test2.jsp</url-pattern> </filter-mapping>