Servlet学习笔记(四):Servlet的请求与响应

时间:2022-10-17 21:02:34

客户端浏览器发送一个请求,服务器作出一系列操作后作出一个响应,发送给客户端,完成一次Web过程过程操作。Web编程的过程就是通过分析客户需要什么信息或者进行了什么操作,然后进行一系列的处理,最后通过响应结果显示给客户。即一次请求-响应的过程。


一、请求-HttpServletRequest对象


客户端浏览器的请求被封装成一个HttpServletRequest对象。所有的信息包括请求的地址,请求的参数,提交的数据,上传的文件,客户端的IP地址甚至客户端操作系统都包含在HttpServletRequest对象中。


封装信息以及获取的方法:

1、编码信息和文档类型。

1)编码信息:设置与获取编码信息

A、request.setCharacterEncoding("UTF-8") :设置编码,统一使用 setCharacterEncodingFilter 

B、request.getCharacterEncoding() :获取编码方法。

2)文档信息:设置与获取文档信息

A、response.setContentType("text/html") :设置 文档类型为HTML类型。这边可以设置输出数据的类型,text/html、image/jpeg、application/msword

B、request.getContentType() :获取文档类型。

3)代码示例:

[java]  view plain  copy
  1. // 1-设置编码方式,可以用时setCharacterEncodingFilter过滤器统一处理  
  2. request.setCharacterEncoding("UTF-8");// 设置 request 的编码方式  
  3. response.setCharacterEncoding("UTF-8");// 设置 response 的编码方式  
  4. response.setContentType("text/html");// 设置 文档类型为HTML类型  
  5.   
  6. request.getCharacterEncoding();  
  7. request.getContentType();  

2、服务器信息。

1)Authorization信息:request.getAuthType()

2)本地IP, 即服务器IP:request.getLocalAddr()

A、实际项目中,一般会用到java.net包下 InetAddress 来获取服务器的真实 IP 地址:

[java]  view plain  copy
  1. // 2-1 实际项目中,一般会用到java.net包下 InetAddress 来获取服务器的真实 IP 地址  
  2. String myLocalIp = InetAddress.getLocalHost().getHostAddress();// 本地地址,服务器IP地址  
  3. logger.debug("利用java.net包下 InetAddress 来获取服务器真实 IP 地址: " + myLocalIp);  

B、Linux下获取服务器IP地址,InetAddress获取IP的方法在windows下没有问题

[java]  view plain  copy
  1. // InetAddress获取IP的方法在windows下没有问题,在Linux有问题,主要是在linux下返回的是/etc/hosts  
  2. // 中配置的ip地址,而不是网卡的绑定地址。现在改用网卡的绑定地址,可以取到本机的ip地址:  
  3. // 利用NetworkInterface 可以封装成一个方法  
  4. String serverip = null;  
  5. Enumeration<NetworkInterface> netInterfaces = null;  
  6. netInterfaces = NetworkInterface.getNetworkInterfaces();  
  7. while (netInterfaces.hasMoreElements()) {  
  8.     NetworkInterface ni = netInterfaces.nextElement();  
  9.     // System.out.println("DisplayName:" + ni.getDisplayName());  
  10.     // System.out.println("Name:" + ni.getName());  
  11.     Enumeration<InetAddress> ips = ni.getInetAddresses();  
  12.     while (ips.hasMoreElements()) {  
  13.         InetAddress ip = ips.nextElement();  
  14.   
  15.         // IP地址分为普通地址和特殊地址。利用InetAddress类提供的十个方法来确定一个IP地址是否是一个特殊的IP地址。  
  16.         // 判断是否地区本地地址  
  17.         if (ip.isSiteLocalAddress()) {  
  18.             serverip = ip.getHostAddress();  
  19.             break;  
  20.         }  
  21.     }  
  22. }  
  23. logger.debug("Linux下 来获取服务器真实 IP 地址: " + serverip);  


3)本地名称, 即服务器名称: request.getLocalName()

4)本地端口号, 即Tomcat 端口号: request.getLocalPort()

5)本地环境: Locale locale = request.getLocale();

[java]  view plain  copy
  1. Locale locale = request.getLocale();// 本地环境  
  2. String localLangurage = getLocaleLangurage(locale);// 语言环境  
  3. String localCountry = locale.getCountry();// 国家  

6)服务器名称:request.getServerName()

7)服务器端口:request.getServerPort()


3、客户端信息。

1)远程IP,即客户端IP:request.getRemoteAddr()

2)远程端口,即客户端端口:request.getRemotePort()

3)客户端的IP,往往会有代理,所以一般的获取方法,需要处理代理信息:

[java]  view plain  copy
  1.         // 客户端的IP,往往会有代理,所以一般的获取方法,需要处理信息  
  2.         String realCusIp = getRealCusIpAddr(request);//真实客户端IP地址  
  3.   
  4. /**   
  5.  * 获得用户真实IP   
  6.  *   
  7.  * @param request 请求对象   
  8.  * @return 真实IP地址   
  9.  */    
  10. public String getRealCusIpAddr(HttpServletRequest request) {    
  11.     String ip = request.getHeader("x-forwarded-for");    
  12.     if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {    
  13.         ip = request.getHeader("Proxy-Client-IP");    
  14.     }    
  15.     if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {    
  16.         ip = request.getHeader("WL-Proxy-Client-IP");    
  17.     }    
  18.     if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {    
  19.         ip = request.getRemoteAddr();    
  20.     }    
  21.     return ip;    
  22. }   

4)远程用户:request.getRemoteUser()。如果提供了Authorization头,则代表其用户部分。它代表发出请求的用户的名字。


4、获取请求信息。

1)获取本次请求的协议信息

A、协议,这里为HTTP协议:request.getProtocol()

B、协议头,这里为Http: request.getScheme()


2)获取头信息 利用浏览器都可以看到

A、浏览器支持的格式,访问Accept的HTTP头: request.getHeader("accept")

B、从哪个页面单机链接到了本页:直接输入为空。request.getHeader("referer")

C、User Agent 信息:request.getHeader("user-agent")

D、其他:request.getHeader("Host")  | request.getHeader("Accept-Language") | 

 request.getHeader("Accept-Encoding") | request.getHeader("Connection")| 

  request.getHeader("Cookie");


3)获取本次请求的一些基本信息

A、访问的方式:Get还是Post。request.getMethod()

B、查询字符串,即访问时 ? 后面的字符串。request.getQueryString()

C、用户请求的URI:request.getRequestURI(),权限使用。

D、用户请求的URL: request.getRequestURL()

用户请求的URL: http://localhost:8080/JavaWeb/servlet/RequestServlet,那么用户请求的URI为: /JavaWeb/servlet/RequestServlet 


4)获取请求的Servlet的信息

A、Context路径:request.getContextPath()。上下文路径,一般是“/工程名”,如:/JavaWeb

B、Servlet的路径: request.getServletPath()。访问的servlert的路径,一般可以在filter中使用,作为拦截。如:/servlet/RequestServlet 。

C、URL中Servlet路径之后、查询字符串之前的那部分: request.getPathInfo()

D、映射到服务器实际路径之后的路径信息: getPathTranslated()

F、request.getServletPath() 和 request.getPathInfo()的差别,见文章


5、其他信息。

1)客户端Session的ID: request.getRequestedSessionId()

2)获取Session信息:request.getSession()

3)获取CooKie信息:request.getCookies()

4)当前授权用户的名称: request.getUserPrincipal()

5)本Servlet运行的服务器信息:this.getServletContext().getServerInfo() 


6、附加补充:利用以下四个方法,获取绝对路径。也可以单独使用getContextPath()获取相对路径。

[java]  view plain  copy
  1. String path = request.getContextPath();  
  2. String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";  

在实际项目中可以放入某个公用页面,这样可以解决大部分的路径问题。


7、完整的代码。

[java]  view plain  copy
  1. package servlet.base;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.UnsupportedEncodingException;  
  5. import java.net.InetAddress;  
  6. import java.net.NetworkInterface;  
  7. import java.net.SocketException;  
  8. import java.net.UnknownHostException;  
  9. import java.security.Principal;  
  10. import java.util.Enumeration;  
  11. import java.util.Locale;  
  12.   
  13. import javax.servlet.ServletException;  
  14. import javax.servlet.http.Cookie;  
  15. import javax.servlet.http.HttpServlet;  
  16. import javax.servlet.http.HttpServletRequest;  
  17. import javax.servlet.http.HttpServletResponse;  
  18. import javax.servlet.http.HttpSession;  
  19.   
  20. import org.apache.log4j.Logger;  
  21.   
  22. import util.IPSeeker;  
  23.   
  24. /** 
  25.  *  
  26.  * RequestServlet.java 
  27.  *  
  28.  * @title HttpServletRequest-请求 
  29.  * @description 
  30.  * @author SAM-SHO 
  31.  * @Date 2014-9-26 
  32.  */  
  33. public class RequestServlet extends HttpServlet {  
  34.   
  35.     private static final long serialVersionUID = 1L;  
  36.   
  37.     // 一定要把log4j的jar包放入lib目录下,不能只是添加build path,不然类加载器加载不到  
  38.     public Logger logger = Logger.getLogger(this.getClass());  
  39.   
  40.     public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  41.         log("使用servlet内置的log, 调用了doGet方法");  
  42.         doService(request, response);  
  43.   
  44.     }  
  45.   
  46.     public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  47.         doService(request, response);  
  48.   
  49.     }  
  50.   
  51.     /** 
  52.      * 通用业务方法 
  53.      *  
  54.      * @param request 
  55.      * @param response 
  56.      * @throws UnsupportedEncodingException 
  57.      * @throws UnknownHostException 
  58.      * @throws SocketException 
  59.      */  
  60.     private void doService(HttpServletRequest request, HttpServletResponse response) {  
  61.   
  62.         try {  
  63.   
  64.             /** 1-编码方法 ************************************************************************/  
  65.   
  66.             // 1-设置编码方式,可以用时setCharacterEncodingFilter过滤器统一处理  
  67.             request.setCharacterEncoding("UTF-8");// 设置 request 的编码方式  
  68.             response.setCharacterEncoding("UTF-8");// 设置 response 的编码方式  
  69.             response.setContentType("text/html");// 设置 文档类型为HTML类型  
  70.               
  71.             request.getCharacterEncoding();  
  72.             request.getContentType();  
  73.   
  74.             /** 2-获取服务器信息 ********************************************************************/  
  75.   
  76.             // 2-0-基本的获取服务器信息  
  77.             String authType = request.getAuthType();// Authorization头  
  78.             String localAddr = request.getLocalAddr();// 本地IP, 即服务器IP  
  79.             String localName = request.getLocalName();// 本地名称, 即服务器名称  
  80.             int localPort = request.getLocalPort();// 本地端口号, 即Tomcat 端口号  
  81.             Locale locale = request.getLocale();// 本地环境  
  82.             String localLangurage = getLocaleLangurage(locale);// 语言环境  
  83.             String localCountry = locale.getCountry();// 国家  
  84.             logger.debug("验证: " + authType + " |服务器IP: " + localAddr + " |服务器名称: " + localName + " |端口号: " + localPort + " |用户的语言环境: " + localLangurage + " |国家: " + localCountry);  
  85.   
  86.             String serverName = request.getServerName();// 服务器名称  
  87.             int serverPort = request.getServerPort();// 服务器端口  
  88.             logger.debug("服务器名称: " + serverName + " |服务器端口: " + serverPort);  
  89.   
  90.             // 2-1 实际项目中,一般会用到java.net包下 InetAddress 来获取服务器的真实 IP 地址  
  91.             String myLocalIp = InetAddress.getLocalHost().getHostAddress();// 本地地址,服务器IP地址  
  92.             logger.debug("利用java.net包下 InetAddress 来获取服务器真实 IP 地址: " + myLocalIp);  
  93.   
  94.             // 2-2  
  95.             // InetAddress获取IP的方法在windows下没有问题,在Linux有问题,主要是在linux下返回的是/etc/hosts  
  96.             // 中配置的ip地址,而不是网卡的绑定地址。现在改用网卡的绑定地址,可以取到本机的ip地址:  
  97.             // 利用NetworkInterface 可以封装成一个方法  
  98.             String serverip = null;  
  99.             Enumeration<NetworkInterface> netInterfaces = null;  
  100.             netInterfaces = NetworkInterface.getNetworkInterfaces();  
  101.             while (netInterfaces.hasMoreElements()) {  
  102.                 NetworkInterface ni = netInterfaces.nextElement();  
  103.                 // System.out.println("DisplayName:" + ni.getDisplayName());  
  104.                 // System.out.println("Name:" + ni.getName());  
  105.                 Enumeration<InetAddress> ips = ni.getInetAddresses();  
  106.                 while (ips.hasMoreElements()) {  
  107.                     InetAddress ip = ips.nextElement();  
  108.   
  109.                     // IP地址分为普通地址和特殊地址。利用InetAddress类提供的十个方法来确定一个IP地址是否是一个特殊的IP地址。  
  110.                     // 判断是否地区本地地址  
  111.                     if (ip.isSiteLocalAddress()) {  
  112.                         serverip = ip.getHostAddress();  
  113.                         break;  
  114.                     }  
  115.                 }  
  116.             }  
  117.             logger.debug("Linux下 来获取服务器真实 IP 地址: " + serverip);  
  118.   
  119.             /** 3-获取客户端信息 *********************************************************************/  
  120.   
  121.             // 3- 获取客户端基本信息  
  122.             String remoteAddr = request.getRemoteAddr();// 远程IP,即客户端IP  
  123.             int remotePort = request.getRemotePort();// 远程端口,即客户端端口  
  124.             String remoteUser = request.getRemoteUser();// 远程用户,如果提供了Authorization头,则代表其用户部分。它代表发出请求的用户的名字。  
  125.             logger.debug("客户端IP: " + remoteAddr + " |客户端端口: " + remotePort + " |远程用户: " + remoteUser);  
  126.   
  127.             // 客户端的IP,往往会有代理,所以一般的获取方法,需要处理信息  
  128.             String realCusIp = getRealCusIpAddr(request);//真实客户端IP地址  
  129.             logger.debug("客户端真实IP,附带代理的IP地址: "+realCusIp);  
  130.               
  131.               
  132.             /** 4-获取请求信息 *********************************************************************/  
  133.               
  134.             // 4-1 获取本次请求的协议信息  
  135.             String protocol = request.getProtocol();// 协议,这里为HTTP协议  
  136.             String scheme = request.getScheme();// 协议头,这里为Http  
  137.             logger.debug("协议: " + protocol + " |协议头: " + scheme);  
  138.   
  139.             // 4-2 获取头信息 利用浏览器都可以看到  
  140.             String accept = request.getHeader("accept");// 浏览器支持的格式,访问Accept的HTTP头  
  141.             String referer = request.getHeader("referer");// 从哪个页面单机链接到了本页  
  142.             String userAgent = request.getHeader("user-agent");// User Agent 信息,  
  143.                                                                 // 包括操作系统及版本号、浏览器类型及版本号  
  144.             request.getHeader("Host");                 
  145.             request.getHeader("Accept-Language");  
  146.             request.getHeader("Accept-Encoding");  
  147.             request.getHeader("Connection");  
  148.             request.getHeader("Cookie");  
  149.   
  150.             logger.debug("浏览器支持的格式: " + getAccept(accept) + " |从哪个页面单机链接到了本页: " + referer + " |操作系统信息: " + getOS(userAgent)+" |客户端浏览器信息 "+ getNavigator(userAgent));  
  151.   
  152.             // 4-3 获取本次请求的一些基本信息  
  153.             String method = request.getMethod();// 访问的方式:Get还是Post  
  154.             String queryString = request.getQueryString();// 查询字符串,即访问时 ? 后面的字符串  
  155.             String requestURI = request.getRequestURI();// 用户请求的URI  
  156.             StringBuffer requestURL = request.getRequestURL();// 用户请求的URL  
  157.             logger.debug("访问的方式: " + method + " |查询字符串,即访问时 ? 后面的字符串: " + queryString + " |用户请求的URI: " + requestURI + " |用户请求的URL: " + requestURL);  
  158.   
  159.             // 4-4 获取请求的Servlet的信息  
  160.             String contextPath = request.getContextPath();  // Context路径  
  161.             String servletPath = request.getServletPath();  // Servlet的路径  
  162.             String pathInfo = request.getPathInfo();    // URL中Servlet路径之后、查询字符串之前的那部分。  
  163.             String pathTranslated = request.getPathTranslated(); // 映射到服务器实际路径之后的路径信息。  
  164.               
  165.               
  166.             /** 5-其他信息 *********************************************************************/  
  167.             // 5-1 其他信息  
  168.             String requestedSessionId = request.getRequestedSessionId(); // 客户端Session的ID  
  169.             HttpSession session = request.getSession(); // 获取Session信息  
  170.             Cookie[] cookies = request.getCookies(); //获取CooKie信息  
  171.             Principal userPrincipal = request.getUserPrincipal(); // 当前授权用户的名称  
  172.               
  173.             String serverInfo = this.getServletContext().getServerInfo(); // 本Servlet运行的服务器信息  
  174.   
  175.             logger.debug("Context路径: " + contextPath + " |Servlet的路径: " + servletPath + " |本Servlet运行的服务器信息: " + serverInfo + " |客户端Session的ID: " + requestedSessionId);  
  176.   
  177.   
  178.   
  179.         } catch (Exception e) {  
  180.             e.printStackTrace();  
  181.         }  
  182.     }  
  183.   
  184.     /** 
  185.      * linux下获取服务器真实 IP 
  186.      *  
  187.      * @return 
  188.      */  
  189.     public static String getServerIP() {  
  190.         String serverip = "";  
  191.   
  192.         try {  
  193.             // InetAddress addr = InetAddress.getLocalHost();  
  194.             // serverip = addr.getHostAddress();  
  195.             // Modify by YiQiang 20130710  
  196.             // InetAddress获取IP的方法在windows下没有问题,在Linux有问题(下只是读取/etc/hosts下的配置)  
  197.             Enumeration<NetworkInterface> netInterfaces = null;  
  198.             netInterfaces = NetworkInterface.getNetworkInterfaces();  
  199.             while (netInterfaces.hasMoreElements()) {  
  200.                 NetworkInterface ni = netInterfaces.nextElement();  
  201.                 Enumeration<InetAddress> ips = ni.getInetAddresses();  
  202.                 while (ips.hasMoreElements()) {  
  203.                     InetAddress ip = ips.nextElement();  
  204.                     if (ip.isSiteLocalAddress()) {  
  205.                         serverip = ip.getHostAddress();  
  206.                         break;  
  207.                     }  
  208.                 }  
  209.             }  
  210.         } catch (Exception ex) {  
  211.             serverip = "127.0.0.1";  
  212.         }  
  213.         return serverip;  
  214.     }  
  215.   
  216.     /** 
  217.      * 用户的语言环境 
  218.      *  
  219.      * @param locale 
  220.      * @return 语言环境名称 
  221.      */  
  222.     private String getLocaleLangurage(Locale locale) {  
  223.         if (Locale.SIMPLIFIED_CHINESE.equals(locale))  
  224.             return "简体中文";  
  225.         if (Locale.TRADITIONAL_CHINESE.equals(locale))  
  226.             return "繁体中文";  
  227.         if (Locale.ENGLISH.equals(locale))  
  228.             return "英文";  
  229.         if (Locale.JAPANESE.equals(locale))  
  230.             return "日文";  
  231.         return "未知语言环境";  
  232.     }  
  233.   
  234.     /** 
  235.      * @param accept 
  236.      * @return 客户端浏览器接受的文件类型 
  237.      */  
  238.     private String getAccept(String accept) {  
  239.         StringBuffer buffer = new StringBuffer();  
  240.         if (accept.contains("image/gif"))  
  241.             buffer.append("GIF 文件, ");  
  242.         if (accept.contains("image/x-xbitmap"))  
  243.             buffer.append("BMP 文件, ");  
  244.         if (accept.contains("image/jpeg"))  
  245.             buffer.append("JPG 文件, ");  
  246.         if (accept.contains("application/vnd.ms-excel"))  
  247.             buffer.append("Excel 文件, ");  
  248.         if (accept.contains("application/vnd.ms-powerpoint"))  
  249.             buffer.append("PPT 文件, ");  
  250.         if (accept.contains("application/msword"))  
  251.             buffer.append("Word 文件, ");  
  252.         return buffer.toString().replaceAll(", $""");  
  253.     }  
  254.   
  255.     /** 
  256.      * @param ip 
  257.      *            IP地址 
  258.      * @return IP地址对应的物理位置 
  259.      */  
  260.     private String getAddress(String ip) {  
  261.   
  262.         try {             
  263.             return IPSeeker.getInstance().getAddress(ip);  
  264.         } catch (Exception e) {  
  265.             e.printStackTrace();  
  266.         }  
  267.         return "未知区域";  
  268.   
  269.     }  
  270.   
  271.     /** 
  272.      * @param userAgent 
  273.      * @return 客户端浏览器信息 
  274.      */  
  275.     private String getNavigator(String userAgent) {  
  276.         if (userAgent.indexOf("TencentTraveler") > 0)  
  277.             return "腾讯浏览器";  
  278.         if (userAgent.indexOf("Maxthon") > 0)  
  279.             return "Maxthon浏览器";  
  280.         if (userAgent.indexOf("MyIE2") > 0)  
  281.             return "MyIE2浏览器";  
  282.         if (userAgent.indexOf("Firefox") > 0)  
  283.             return "Firefox浏览器";  
  284.         if (userAgent.indexOf("MSIE") > 0)  
  285.             return "IE 浏览器";  
  286.         if(userAgent.indexOf("Chrome") > 0)  
  287.             return "Chrome 浏览器";  
  288.         return "未知浏览器";  
  289.     }  
  290.   
  291.     /** 
  292.      * @param userAgent 
  293.      * @return 客户端操作系统 
  294.      */  
  295.     private String getOS(String userAgent) {  
  296.         if (userAgent.indexOf("Windows NT 5.1") > 0)  
  297.             return "Windows XP";  
  298.         if (userAgent.indexOf("Windows 98") > 0)  
  299.             return "Windows 98";  
  300.         if (userAgent.indexOf("Windows NT 5.0") > 0)  
  301.             return "Windows 2000";  
  302.         if (userAgent.indexOf("Linux") > 0)  
  303.             return "Linux";  
  304.         if (userAgent.indexOf("Unix") > 0)  
  305.             return "Unix";  
  306.         if (userAgent.indexOf("Windows NT 6.1") > 0)  
  307.             return "Windows 7";  
  308.         return "未知";  
  309.     }  
  310.       
  311.     /**   
  312.      * 获得用户真实IP   
  313.      *   
  314.      * @param request 请求对象   
  315.      * @return 真实IP地址   
  316.      */    
  317.     public String getRealCusIpAddr(HttpServletRequest request) {    
  318.         String ip = request.getHeader("x-forwarded-for");    
  319.         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {    
  320.             ip = request.getHeader("Proxy-Client-IP");    
  321.         }    
  322.         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {    
  323.             ip = request.getHeader("WL-Proxy-Client-IP");    
  324.         }    
  325.         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {    
  326.             ip = request.getRemoteAddr();    
  327.         }    
  328.         return ip;    
  329.     }   
  330.   
  331. }  

8、使用头信息request.getHeader("referer"), 实现防盗链。


二、响应-HttpServletResponse

服务器对客户端浏览器作出的响应被封装成一个HttpServletResponse 对象。要对浏览器进行操作,只要要操作HttpServletResponse 对象就可以了。通过HttpServletResponse.getWriter()获得一个 PrintWriter 对象,该对象为 OutputStream 的子类。


1、HttpServletResponse.getWriter():对象只能写字符型的数据。HttpServletResponse.getOutputStream ():写二进制数据,如输出图片等。注意:这两个方法不能同时使用,特别是多层转发的时候,使用的还是同一个request对象,不能同时调用这两个方法。(getOutputStream () has already bean called for this response)

2、输出必须设置输出类型:response.setContentType("image/jpeg"),需要与输出方式统一。例子:输出图片验证码:

[java]  view plain  copy
  1. package servlet.base;  
  2.   
  3. import java.awt.Color;  
  4. import java.awt.Font;  
  5. import java.awt.Graphics2D;  
  6. import java.awt.image.BufferedImage;  
  7. import java.io.IOException;  
  8. import java.util.Random;  
  9.   
  10. import javax.servlet.ServletException;  
  11. import javax.servlet.ServletOutputStream;  
  12. import javax.servlet.http.HttpServlet;  
  13. import javax.servlet.http.HttpServletRequest;  
  14. import javax.servlet.http.HttpServletResponse;  
  15.   
  16. import com.sun.image.codec.jpeg.JPEGCodec;  
  17. import com.sun.image.codec.jpeg.JPEGImageEncoder;  
  18.   
  19. /** 
  20.  *  
  21.  * IdentityServlet.java 
  22.  *  
  23.  * @title 
  24.  * @description 
  25.  * @author SAM-SHO 
  26.  * @Date 2014-9-27 
  27.  */  
  28. public class IdentityServlet extends HttpServlet {  
  29.   
  30.     private static final long serialVersionUID = -479885884254942306L;  
  31.   
  32.     // 随机字符字典  
  33.     public static final char[] CHARS = { '2''3''4''5''6''7''8''9''A',   
  34.                                         'B''C''D''E''F''G''H''J''K',   
  35.                                         'L''M''N''P''Q''R''S''T''U',   
  36.                                         'V''W''X''Y''Z' };  
  37.   
  38.     public static Random random = new Random();// 随机数  
  39.   
  40.   
  41.   
  42.     public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  43.   
  44.         response.setContentType("image/jpeg");// 设置输出类型  
  45.   
  46.         String randomString = getRandomString();// 获取随机字符串  
  47.         request.getSession(true).setAttribute("randomString", randomString);// 放入session  
  48.   
  49.         int width = 100// 图片宽度  
  50.         int height = 30// 图片高度  
  51.   
  52.         Color color = getRandomColor();// 随机颜色,用于背景色  
  53.         Color reverse = getReverseColor(color);// 反色,用于前景色  
  54.   
  55.         BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);//创建一个彩色图片  
  56.         Graphics2D g = bi.createGraphics();// 获取绘图对象  
  57.         g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 16));//设置字体  
  58.         g.setColor(color);//设置颜色  
  59.         g.fillRect(00, width, height);// 绘制背景  
  60.         g.setColor(reverse);//设置颜色  
  61.         g.drawString(randomString, 1820);//绘制随机字符  
  62.   
  63.         //画最多100个噪音点  
  64.         for (int i = 0, n = random.nextInt(100); i < n; i++) {  
  65.             g.drawRect(random.nextInt(width), random.nextInt(height), 11);  
  66.         }  
  67.   
  68.         // 转成JPEG格式  
  69.         ServletOutputStream out = response.getOutputStream();  
  70.         JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);//编码器  
  71.         encoder.encode(bi);//对图片进行编码  
  72.         out.flush();  
  73.     }  
  74.       
  75.     /** 
  76.      * 获取 6 位 随机数 
  77.      *  
  78.      * @return 
  79.      */  
  80.     public static String getRandomString() {  
  81.         StringBuffer buffer = new StringBuffer();  
  82.         for (int i = 0; i < 6; i++) {// 循环 6 次  
  83.             buffer.append(CHARS[random.nextInt(CHARS.length)]);// 每次取一个随机字符  
  84.         }  
  85.         return buffer.toString();  
  86.     }  
  87.   
  88.     /** 
  89.      * 获取随机的颜色 
  90.      *  
  91.      * @return 
  92.      */  
  93.     public static Color getRandomColor() {  
  94.         return new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255));  
  95.     }  
  96.   
  97.     /** 
  98.      * 返回某颜色的反色 
  99.      *  
  100.      * @param c 
  101.      * @return 
  102.      */  
  103.     public static Color getReverseColor(Color c) {  
  104.         return new Color(255 - c.getRed(), 255 - c.getGreen(), 255 - c.getBlue());  
  105.     }  
  106.       
  107.     /** 
  108.      * 测试 
  109.      * @param args 
  110.      */  
  111.     public static void main(String[] args) {  
  112.         System.out.println(getRandomString());  
  113.     }  
  114. }  



3、控制浏览器是否缓存。

1)不缓存。

[java]  view plain  copy
  1. response.setHeader("progma""no-cache");  
  2. response.setHeader("Cache-Control""no-cache");  
  3. response.setHeader("Cache-Control""no-store");  
  4. response.setDateHeader("Expires"0);//时间头  


2)利用Expires时间头,控制页面缓存。记得加上当前时间。System.currentTimeMillis()

[java]  view plain  copy
  1. //设置缓存 一定要是当前时间 + 控制的缓存时间  
  2. response.setDateHeader("Expires", System.currentTimeMillis() + 1000*3600);  


4、利用HttpServletResponse实现下载:

[java]  view plain  copy
  1. // 2-1实现下载  
  2. // 注意中文的文件名文件下载时,注意编码 URLEncoder  
  3. // 使用getRealPath(),为了实现文件名称的显示  
  4.         String realPath = this.getServletContext().getRealPath("/downLoad/mcm.png");  
  5. String realPath = this.getServletContext().getRealPath("/downLoad/蒙奇奇.jpg");//中文  
  6. System.out.println("文件的绝对路径: " + realPath);  
  7.   
  8. String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);  
  9. System.out.println("文件的名称为: " + fileName);  
  10.   
  11. //设置浏览器下载  
  12. response.setHeader("content-disposition""attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));  
  13.   
  14. // 固定输出  
  15. InputStream in = null;  
  16. OutputStream out = null;  
  17. try {  
  18.       
  19.     in = new FileInputStream(realPath);  
  20.     int len = 0;  
  21.     byte[] buffer = new byte[1024];  
  22.     out = response.getOutputStream();  
  23.     while ((len = in.read(buffer)) > 0) {  
  24.         out.write(buffer, 0, len);  
  25.     }  
  26.   
  27. }finally{  
  28.     if(in != null) {  
  29.         try {  
  30.             in.close();  
  31.         } catch (Exception e) {  
  32.         }  
  33.   
  34.     }  
  35. }  


三、Servlet的跳转


利用Servlet的跳转,实现了MVC框架,把程序分成三个独立模块:业务模块(Model)、视图模块(View)、控制模块(Control)。其中Model负责处理业务,View负责显示数据,Control负责控制。在struts框架中三个部分分别为3个Servlet,程序在3个Servlet之间跳转。

Servlet的跳转有两种方式:转发(Forward)和重定向(Redirect)。


1、转发(Forward):

是通过 RequestDispatcher 对象的 forward()方法实现。RequestDispatcher 可以通过HttpServletRequest 的getRequestDispatcher()方法获得。或者使用ServletContext.getRequestDispatcher()方法获取。

1)代码:

[java]  view plain  copy
  1. RequestDispatcher dispatcher = request.getRequestDispatcher("/servlet/LifecyclesServlet");  
  2. dispatcher.forward(request, response);  

2)getRequestDispatcher()方法的参数必须为以“/”开始,“/”表示本Web应用程序的根路径。如果要跳转到Servlet为http://localhost:8080/servlet/RequestServlet。则参数应该为“/servlet/RequestServlet”。


3)当使用Forward形式跳转Servlet时,地址栏会显示跳转前的Servlet访问地址。因为该跳转是在服务器端实现,客户端浏览器并不知道该跳转动作。也就是说Forward跳转对客户端浏览器是透明的。

4)Forward是最常用的方式。在struts等框架中,都是用Servlet来处理用户请求,把结果通过request.setAttribute()放到 request 中,然后Forward到JSP显示。

5)当执行Forward动作的时候不能有任何输出到达客户端,否则会抛出illegalStateException。也就是在 Forward 之前尽量不要使用 out.println()语句向客户端输出结果。

6)转发:同一个HttpServletRequest 这时,web数据的共享要使用Request 域即可。



2、重定向(Redirect)

1)重定向是利用服务器返回的状态来实现的。客户端浏览器请求服务器的时候,服务器端会返回一个状态码。服务器端通过 HttpServletResponse 的 setStatus()方式设置状态码。如果服务器返回301 或者302,则浏览器会到新的网址重新请求该资源。状态码的意思如下:

Servlet学习笔记(四):Servlet的请求与响应

2)301 、302都表示重定向,区别是 301是永久性重定向,302是临时性重定向。下面的代码将访问该Servlet的请求重定向到另一个网址。

response.setStates(HttpServletResponse.SC_MOVED_PERMANENTLY);//设置状态码为301

response.setHeader("Location","http://www.baidu.com") 新网址


3)HttpServletResponse 类中把重用的状态码封装成了静态常量。并且把setStates()与setHeader()方法封装成另一个方法sendRedirect(String location),只需要调用sendRedirect就能实现重定向。

4)与转发不同,重定向(Redirect)的跳转是在客户端实现的。实际上客户端浏览器请求了 2 次服务器,第1 次获取重定向的状态码与重定向的网址,第 2 次访问真实地址。

5)重定向:不同的HttpServletRequest 对象,每一次访问都会new一个HttpServletRequest 对象。这时,web数据的共享要使用 session 域和 context 域。


[java]  view plain  copy
  1. // request域的数据,转发可以获取,重定向获取不到  
  2. String data = "12345";  
  3. request.setAttribute("data", data);  
  4.   
  5. /*********   转发    *******************/  
  6. // 转发,可以获取request域的数据。只有一个请求,服务器跳转。url不会变化。  
  7. // 1-1 获取 RequestDispatcher对象,然后转发  
  8. RequestDispatcher rd = request.getRequestDispatcher("/MyJsp.jsp");  
  9. RequestDispatcher rd2 = getServletContext().getRequestDispatcher("/MyJsp.jsp");  
  10. rd.forward(request, response);  
  11. rd2.forward(request, response);  
  12.   
  13. // 2-1 直接转发  
  14. request.getRequestDispatcher("/MyJsp.jsp").forward(request, response);  
  15. getServletContext().getRequestDispatcher("/MyJsp.jsp").forward(request, response);  
  16.   
  17.   
  18. /*********   重定向    *******************/  
  19. // 重定向 ,2次request请求,客户端跳转跳转,url显示第二次跳转的url地址,不能获取request域的数据。  
  20. response.sendRedirect("/MyJsp.jsp");  

3、自动刷新(Refresh)

自动刷新不仅可以实现一段时间之后自动跳转到另一个页面,还可以实现一段时间之后刷新本页面。Servlet中通过设置HttpServletResponse 对象的Header属性实现自动刷新效果。例如:

[java]  view plain  copy
  1. response.setHeader("Refresh","1000; url=http://www.baidu.com")  

1)其中 1000 为时间,单位为毫秒。
2)URL参数指定的网址就是1 秒之后跳转的页面。当URL设置的路径为Servlet自己的路径时,就会每隔1秒钟自动舒鑫页面一次。

3)自动刷新与重定向原理是差不多。如果时间设为 0,把URL设为另一个网址,效果就是重定向。

[java]  view plain  copy
  1. response.setHeader("Refresh","0; url=http://www.baidu.com")