从来就没有救世主  也不靠神仙皇帝  要创造人类的幸福  全靠我们自己  

Servlet

 

 继承体系:

  

 

 

 

 

  Servlet是运行在服务器端的Java应用程序,由Servlet容器管理。当客户端对容器发送HTTP请求时,容器通知对应的Servlet对象处理。

    ①客户端发起HTTP请求

    ②容器收到请求,根据资源名匹配web.xml配置文件,找到字节码文件并加载进内存(Class.forName())

    ③创建对象,调用一次该对象的init方法

    ④调用service方法,处理请求

    ⑤服务器正常关闭时,调用一次destroy方法释放资源,然后完全销毁servlet对象

 

  Servlet对象创建时机:web.xml相应servlet标签的<load-on-startup>

    ①第一次访问时创建:不配置此标签或配置为负数

    ②服务器启动时创建:配置为0或正整数

 

  一个Servlet在内存中只有一个对象(单例)

 

1. Servlet接口

  常用方法:

void init(ServletConfig config)  Servlet实例化后,容器调用一次此方法完成一些初始化工作
void service(ServletRequest request,ServletResponse response)  处理请求
void destroy()  Servlet对象从容器中移除时,容器调用此方法释放资源
ServletConfig getServletConfig()  获取Servler对象配置信息
String getServletInfo()  获取Servler信息

 

  init:让Servlet对象在处理客户请求前完成初始化工作,如建立数据库连接、获取配置信息等

  service:通过ServletRequest对象获得客户端相关信息和请求信息,通过ServletResponse对象的方法设置响应信息

 

2.  ServletConfig接口

  方法:

String getInitParameter(String name)  获取名为name的初始化参数的值
Enumeration getInitParameterNames()   获取所有初始化参数名的枚举集合
ServletContext getServletContext()    获取Servlet上下文对象
String getServletName()               获取Servlet对象的实例名

 

3. HttpServlet抽象类

  重载service方法,提供如下方法需要自定义实现:

void doGet(HttpServletRequest req,HttpServletResponse res)
void doPost(HttpServletRequest req,HttpServletResponse res)
void doHead(HttpServletRequest req,HttpServletResponse res)
void doPut(HttpServletRequest req,HttpServletResponse res)
void doDelete(HttpServletRequest req,HttpServletResponse res)
void doTrace(HttpServletRequest req,HttpServletResponse res)
void doOptions(HttpServletRequest req,HttpServletResponse res)

 

4. RequestDispatcher接口

  ServletRequest:

RequestDispatcher getRequestDispatcher(String path)

  RequestDispatcher的方法:

void forward(ServletRequest request,ServletResponse response)
void include(ServletRequest request,ServletResponse response)

 

5. ServletContext接口 

  ServletRequest、ServletConfig接口都有getServletContext方法(同一个web应用中获取到的是同一个ServletContext对象) 

  ServletContext的对象代表整个web应用,可和web应用的容器通信

(1)获取MIME类型

  MIME类型格式:大类型/小类型  如 text/html   image/jpg

String getMimeType(String file)

(2)域对象:共享数据

  由于ServletContext代表整个web应用,因此通过此类对象可使数据在当前应用的所有servlet里面共享

//ServletContext
void setAttribute(String name,Object object)
void removeAttribute(String name)
Object getAttribute(String name)

  ServletRequest类对象的setAttribute、getAttribute的数据只能在一次请求中共享

(3)文件(在服务器中的)真实路径

//ServletContext
String getRealPath(String path) //参数以web应用路径为基础路径

 

-------------------------------------------------------------------------------------------------------

HTTP:

1. 请求消息数据格式

  请求行:请求方式  请求url  请求协议/版本

    GET方式的参数在请求行中

    POST方式的参数在请求体中

  请求头:名称:值

    Host:服务器主机

    User-Agent:浏览器版本信息

    Accept:浏览器可接受的数据格式

    Accept-Language:浏览器接受的语言

    Accept-Encoding:浏览器可接受的编码

    Connection:连接

    Referer:告诉服务器当前请求从哪里来

      ①防盗链

      ②做统计工作

  请求空行:分隔请求头和请求体

  请求体:POST方式才有,封装了请求参数

 

2. 响应消息数据格式

  响应行:协议/版本  响应状态码  状态码描述

    (1)1xx    服务器接收客户端信息,但没有接收完成,等待一段时间后,服务器发送1xx状态码给客户端

    (2)2xx    成功。

    (3)3xx    重定向  302(重定向)   304(访问缓存)

    (4)4xx    客户端错误  404(请求路径没有对应的资源)   405(请求方式没有对应的方法)

    (5)5xx    服务器端错误

  响应头:

    Content-Type:本次响应的数据格式和编码格式

    Content-Length:

    Content-disposition:告知浏览器以什么格式打开响应体数据

      默认:in-line

      attachment:以附件形式打开响应体(文件下载)

  响应空行

  响应体: 服务器返回的数据

-------------------------------------------------------------------------------------------------------

  获取请求信息与设置响应数据

1. 获取请求行数据:

//ServletRequest
String getProtocol()    获取协议及版本
String getRemoteAddr()  获取客户机IP
//HttpServlletRequest
String getMethod()      获取请求行中的请求方式
String getContextPath() 获取虚拟目录
String getServletPath() 获取Servlet路径
String getQueryString() 获取GET方式的请求参数
String getRequestURI()  虚拟路径到Servlet路径组成的字符串
StringBuffer getRequestURL() 从http开始到Servlet路径组成的字符串

 

2. 获取请求头数据:

//ServletRequest

//HttpServlletRequest
String getHeader(String name)
Enumeration<String> getHeaders(String name)
Enumeration<String> getHeaderNames()

 

3. 获取请求体数据:

   获取流对象,再从流对象中获取数据

//ServletRequest
BufferedReader getReader()  获取字符输入流
ServletInputStream getInputStream() 获取字节输入流
//HttpServlletRequest

 

4.  其它

(1)获取请求参数的通用方式

//ServletRequest
String getParameter(String name)
String [] getParameterValues(String name)
Enumeration getParameterNames()
Map<String,String[]> getParameterMap()
//HttpServlletRequest

 

  getParameter无法获取Post方式提交的参数问题:

    本地测试遇到了:tomcat 7.0.88  servlet3.1

    网上的说法:①哈希表bug导致,需要修改tomcat配置文件里的maxPostSize、maxParameterCount ------但在配置文件里没找到这两个选项

          ②前端contentType的问题

          ③对于请求体数据,流式获取的原因

    目前是由于第③种原因导致的:对于post的请求体参数,只能选择getReader、getInputStream、getPatameter方法里的一个,大概可以理解为使用其中一个方法后,请求体所有数据放到了该方法返回的流对象上,如果再用其它两种方法获取,就获取不到数据了。

 

  中文乱码问题:

    取参数前,设置request的编码 request.setCharacterEncoding("utf-8");  【仅对POST方式请求,在获取请求体参数乱码时有效】

    对于GET方式获取参数乱码,Tomcat环境下在server.xml的<Connector>内添加  URIEncoding="UTF-8"

 

(2)请求转发:服务器内部的资源跳转方式(地址栏信息是不变的)

  ServletRequest接口的方法:

//①通过ServletRequest对象获取请求转发器对象
RequestDispatcher getRequestDispatcher(String path) //path是另一个Servlet的地址
//②使用RequestDispatcher对象进行转发
xxx.forward(request,response)
xxx.include(request,response)

  forward和include的区别:

         

 

    forward:servlet2的response回复给用户,而servlet1的不会   

    include:servlet2的response包含在servlet1的response中,由servlet1回复用户

 

  这个跳转是服务器内部(本项目内)的跳转,是为了多个servlet来实现功能,对用户而言是看不到变化的(即只有一次浏览器请求)    

 

(3)共享数据

  request域:一次请求的范围,可用于请求转发的多个资源中共享资源

//ServletRequest
void setAttribute(String name,Object o) 存储一个数据
Object getAttribute(String name)        获取一个数据
void removeAttribute(String name)       移除一个数据

 

 

(4)获取ServletContext

//ServletRequest
ServletContext getServletContext()

 

 

 

 -------------

  响应

1. 设置响应行

  设置响应码:

//HttpServletResponse
void setStatus(int sc,String sm)

 

2. 设置响应头

//HttpServletResponse
void setHeader(String name,String value)

 

3. 设置响应体 

   获取流,向流中写入数据

//ServletResponse
PrintWriter getWriter()   //字符流
ServletOutputStream getOutputStream()  //字节流

 

4. 其它

(1)重定向

  对浏览器而言,又发起了一次请求

  ①方式一

  告诉浏览器重定向,返回状态码302

  重定向路径在响应头,以 location:地址  给出

response.setStatus(302);
response.setHeader("location","/虚拟路径/资源路径");

 

  ②方式二

//HttpServletResponse
void sendRedirect(String location)

 

(2)中文乱码

  获取流之前设置响应消息编码并告知浏览器以此编码解析数据

//ServletResponse
void setCharacterEncoding(String charset)  // "UTF-8"
void setContentType(String type) //或者用下面的方式告知  //"text/html;charset=UTF-8"
//HttpServletResponse
void setHeader(String name,String value) //设置content-type

 

  

 

  中文文件名乱码问题:

  如果setHeader的值为中文,如下载功能的content-disposition后的提示信息有中文,导致弹出框显示错误(IE、Edge、FireFox)或下载的文件命名错误(Chrome):

  乱码时的写法:

resp.setHeader("content-disposition","attachment;filename="+fileName);

  解决:需要根据浏览器类型和版本设置编码

  

  一个通用的工具类:

import sun.misc.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;


public class DownLoadUtils {

    public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
        if (agent.contains("MSIE")) {
            // IE浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
        } else {
            // 其它浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }
}

  修改后:

String agent = req.getHeader("user-agent");
fileName = DownUtils.getFileName(agent,fileName); //解决中文乱码问题
resp.setHeader("content-disposition","attachment;filename="+fileName);

 

    

 

posted @ 2020-05-21 08:50  T,X  阅读(134)  评论(0编辑  收藏  举报