Servlet



Servlet

Servlet是一个java接口,为我们封装好了处理HTTP请求的各种方法,而从达到浏览器和服务器的交互的目的,主要是处理Http请求并返回响应
Servlet是单例的,多用户访问创建多线程执行,即参数是栈内存独享,而成员变量有线程安全问题,需要加synchonized锁



Tomcat

Tomcat是一个Servlet容器,能运行.class文件,也是Jsp容器能处理动态资源,还是Web服务器也就是说能处理Hmlt,Css等,Tomcat启动时读取webapps下各站点web.xml文件里的信息,加载对应类,然后反射的实例化他们


web.xml常用的xml元素

<web-app> 
    <display-name></display-name> 定义了WEB应用的名字 
    <description></description> 声明WEB应用的描述信息 
    <context-param></context-param> 声明站点范围内的初始化参数

    <filter></filter> 声明一个过滤器
    <filter-mapping></filter-mapping> 与声明的filter关联来映射url
    
    <listener></listener> 声明一个listener
    
    <servlet></servlet> 声明一个servlet
    <servlet-mapping></servlet-mapping> 与声明的servlet关联来映射url
 
    <welcome-file-list></welcome-file-list> 指示服务器在收到引用一个目录名而不是文件名的URL时,使用哪个文件
    
    <error-page></error-page> 在返回特定HTTP状态代码时,或者特定类型的异常被抛出时,能够制定将要显示的页面
</web-app>

元素的配置

<listener> 
    <listerner-class>listener.SessionListener</listener-class> 
</listener>


<context-param> 
    <param-name>ContextParameter</para-name> 
    <param-value>test</param-value> 
    <description>It is a test parameter.</description> 
</context-param> 


<servlet>
    <servlet-name>ServletConfigTest</servlet-name>
    <servlet-class>pratices.ServletConfigTest</servlet-class>  // 完整限定类名
    <init-param>
    	<param-name>name</param-name>
    	<param-value>Howl</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>ServletConfigTest</servlet-name>
    <url-pattern>/ServletConfigTest</url-pattern>
</servlet-mapping>


<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>


<error-page> 
	<error-code>404</error-code> 
	<location>/404.html</location> 
</error-page> 


<filter>
	<filter-name>CharacterEncodingFilter</filter-name>
	<filter-class>
		org.springframework.web.filter.CharacterEncodingFilter
    </filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

其中映射url通配符,容器会减去站点的上下文路径才去匹配

  • 路径匹配:/ 开头,/* 结尾,即 /Howl/*
  • 扩展名匹配: *. 开头,即 *.html
  • 缺省匹配:/ ,即都没找到的就来这个,访问任何资源都是在访问Servlet,缺省就会找图片或网页,再找不到就404(小猫页面)

其中

  • 在web站点启动时就加载创建实例及调用init()方法,可用于定时任务,eg:日志与备份
  • 正数一般是1表示加载实例化,不写或负数则第一次请求才实例化


1. 使用流程


1.1 创建测试类实现Servlet接口,其中有五个方法

public class ServletTest implements Servlet {

	public void destroy() {

	}

	public ServletConfig getServletConfig() {
		return null;
	}

	public String getServletInfo() {
		return null;
	}

	public void init(ServletConfig arg0) throws ServletException {

	}

	public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {

	}
}

1.2 显然service() 是我们处理请求的地方,所以我们在Service()方法里面写入

arg1.getWriter().write("Hello World");  //字符流

1.3 写完Service()是不够的,我们还需要让Tomcat知道怎么调用,何时调用该Servlet,即要在web.xml钟配置他

配置web.xml

<servlet>
    <!-- 配置一个名字 -->
	<servlet-name>ServletTest</servlet-name>
    <!-- 对应的Servlet类 -->
	<servlet-class>com.howl.controller.ServletTest</servlet-class>
</servlet>
<servlet-mapping>
    <!-- 需要映射的Servlet名字 -->
	<servlet-name>ServletTest</servlet-name>
    <!-- 映射地址 -->
	<url-pattern>/HelloWorld</url-pattern>
</servlet-mapping>

1.4 输入对应的映射地址访问



2. Servlet生命周期

  • 加载:Tomcat第一次访问该Servlet时加载对应的Class并且创建该实例,属于单例,并发访问则创建多线程

  • 初始化:实例化后调用Servlet内部的init()函数初始化

  • 处理服务:浏览器访问该类时调用service()方法

  • 销毁:Tomcat关闭或者主动调用destory该类会被销毁

  • 卸载:等待GC,如果有需要再次使用这个Servlet,会重新调用init()方法进行初始化操作。



3. HttpServlet

我们开发时直接继承HttpServlet类,该类实现了Servlet的所有方法,并且增加了HTTP协议的处理方法,比Servlet更有优势,我么只需要重写doGet()和doPost()就可以了

public class ServletTest extends HttpServlet {

    //处理Get请求
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

	}

    //处理Post请求
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

	}
}


4. ServletConfig

每个HttpServlet都有这个对象,用来获取在web.xml里面的单独配置的初始化参数,在web.xml中更加灵活,修改数据不用改动代码 <init-param>

public class servletAuth extends HttpServlet {
    ServletConfig servletConfig = this.getServletConfig();
    String value = servletConfig.getInitParameter("name");
}


5. ServletContext

代表着当前web站点,所有servlet共享该资源,可以直接获取,这里this指代HttpServlet

public class servletAuth extends HttpServlet {
    ServletContext servletContext = this.getServletContext();
    servletContext.getInitParameter("name");
}

可用于Servlet间通信、可获取站点信息/资源

servletContext.setAttribute("name", "object"); //设置域属性,可设置对象
servletContext.getResourceAsStream("address"); //因为代表本站点,所以从根目录开始即与WEB-INF同级

以前类文件和资源文件同级可以直接访问,因为是JVM运行,而现在是Tomcat运行要遵守其目录规则
src下的资源要去classes下访问
与WEB-INF同级可直接访问



6. HttpServletResponse响应

Response向浏览器输出内容,Tomcat每收到一个Http请求就会为其创建request和response对象
Servlet流用完之后,Servlet引擎会从response中取数据,将数据当成响应正文处理


返回数据,Tomcat使用ISO 8859-1,不支持中文

// 响应二进制
response.setHeader("Content-Type", "text/html;charset=UTF-8");     // 设置网页请求头接收编码,
response.getOutputStream().write("你好世界".getBytes("UTF-8"));    // Stream类传输二进制,中文要先变成二进制,不写编码默认用系统的gbk2312,因为调用的是java函数

// 响应字符串
response.setCharacterEncoding("UTF-8");    // 设置响应对象编码
response.getWriter().write("你好世界")    // 此时调用Tomcat的writer会使用自带的ISO编码,需要在前设置

// 简化设置,第一个代表了上面两个
response.setContentType("text/html;charset=UTF-8")

response.setHeader("Content-Type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");

下载

File file = new File("/download/test.png");

FileInputStream fileInputStream = new FileInputStream(file);
ServletOutputStream servletOutputStream = response.getOutputStream();

//设置响应头为下载,后面url编码为了文件名中文能适应
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(file.getName(), "UTF-8"));

int length = 0;
byte[] bytes = new byte[1024];
while( (length = fileInputStream.read(bytes)) != -1 ){
	servletOutputStream.write(bytes, 0, length);
}
servletOutputStream.close();
fileInputStream.close();

重定向

response.sendRedirect("/404.html");//本地发生的,地址栏发生了变化(302)

压缩响应数据,这是浏览器解码

response.setHeader("Content-Encoding","gzip")

自动刷新+跳转

response.setHeader("Refresh","3;url=index.html")

禁止缓存

response.setHeader("Cache-Control","no-cache")

设置Cookie,Cookie后面会介绍

void  addCookie(Cookie cookie)


7. HttpServletRequest

常用方法

request.setCharacterEncoding("UTF-8"); // 设置request编码,针对POST表单,get在url上,不在request中不起作用
request.getRemoteAddr()	// 获取发送请求的IP
request.getRemotePort()   // 获取发送请求的端口
request.getRequestURL()   // 获取请求的完整地址
request.getMethod()      // 获取请求方法,应再补上.equalsIgnoreCase
request.getHeader("请求头参数")   // 获取请求头
request.getPathInfo()    // 获取 / 开头的额外信息,servlet之后,请求参数之前的数据
request.getParameter("userId");		// 获取参数
request.getParameterValues(String name)  // 获取复选框那种多数据的
request.getAttribute()   // 在request对象域上存放数据,可用于转发
request.getRequestDispatcher("/index.html").forward(request,response) // 实现转发,带上域数据,服务器发生的,本地地址栏没变化,而且 / 代表该站点根目录,即WEB-INF同级

获取Cookie

Request.getCookies();  //获得一个数组,里面包含所有对象
Request.getSession();	//获取当前浏览器的Session

get请求中文乱码,Tomcat使用了ISO

byte[] bytes = request.getParameter("name").getBytes("ISO8858-1");
String reallyValue = new String(bytes,"UTF-8");


Http是无状态的,但Cookie会话技术就可以解决这个问题,当浏览器访问服务器时,服务器给浏览器颁发一个Cookie里面记录了SessionId,当浏览器再次访问该服务器时就会带上对应的Cookie,这样服务器就会认识你拉。一个网站可以有多个cookie,每个cookie就是键值对加上必要的信息 eg:过期时间等

构造函数

Cookie(java.lang.String name, java.lang.String value)

常见方法

String	getName()
String  getValue()
void    setValue(java.lang.String newValue)
int	    getMaxAge()
void setSecure(true)  // https才带上
void    setMaxAge(int expiry)    // 负数本次会有有效,0代表删除,因无对应方法,本地也删除,默认-1
String  getPath()
void	setPath()    // 设置资源可以访问的地址,默认是整个页面可以使用,设置之后只有指定path才能使用
String	getDomain()
void    setDomain(java.lang.String pattern)  // 设置域

常见操作

// 设置response的编码
response.setContentType("text/html;charset=UTF-8");

// 实例化一个Cookie,注意导包是导入javax.servlet.http.Cookie,这个包在tomcat下
// URLEncoder在java.net包下,单参构造函数已废弃,中文属于Unicode编码四字节,英文ASCII两字节,需要转码,与早期打印机相关
Cookie cookie = new Cookie("name", URLEncoder.encode("我爱中国", "UTF-8"));

// 设置过期时间,单位为秒,-1有效到浏览器关闭
cookie.setMaxAge(1000);

// 设置额外二级域
cookie.setDomain("a.com");

// 响应头添加set-cookie
response.addCookie(cookie);

// 设置路径,一般cookie整个站点都可以用,但也可以只限制该地址可用
//cookie.setPath("/ServletConfigTest");

/*************************************/


// 返回包含所有对象的数组
Cookie[] cookies = request.getCookies();

for(Cookie cookieLoop : cookies){
	String name = cookieLoop.getName();
	String value = URLDecoder.decode(cookieLoop.getValue(), "UTF-8");
	System.out.println(name + "----" + value);
}


9. HttpSession

Session是记录浏览器状态的机制,解决http无状态的另一种方式,Session能存放对象,并且Session是存在服务器端的,cookie只存字符串,所以Servlet能共享属于某个浏览器的Session

当浏览器访问服务器的Servlet,并且使用了response.getSession()才会自动给该浏览器颁发一个带JESSIONID的Cookie,JESSIONID就是唯一标识浏览器Session的id,该cookie默认生命周期为当前浏览器,所以关闭了浏览器Session就会失效

Session的有效期是访问一次就重置,而cookie的是累计,Session存放于服务器内存,超时会自动删除,默认超时为30min,一般存用户级别数据,即当前会话有效的

Session的活化和钝化下篇Listener有提及
钝化:服务器关闭时还有正常的Session存在并未超时,就会以文件的形式存储起来

活化:服务器再次开启时,恢复存储起来的Session对象

实现该功能的对象需要实现Serializable接口,涉及了序列化


方法

long getCreationTime()		//获取Session被创建时间
String getId() 				//获取Session的id
long getLastAccessedTime() 			//返回Session最后活跃的时间
ServletContext getServletContext() 			//获取ServletContext站点对象
void setMaxInactiveInterval(int var1) 	//设置Session超时时间
int getMaxInactiveInterval() 	//获取Session超时时间
Object getAttribute(String var1) 	//获取Session属性,代替了getValue
Enumeration getAttributeNames() 		//获取Session所有的属性名
void setAttribute(String var1, Object var2) 	//设置Session属性,可存对象,在于域中
void removeAttribute(String var1) 		//移除Session属性
void invalidate() 		//销毁该Session
boolean isNew() 		//该Session是否为新的

常见操作

HttpSession httpSession = request.getSession();
httpSession.setAttribute("Session", "Howl");
		
System.out.println(request.getSession().getAttribute("Session"));

//当浏览器禁止了Cookie的时候,encodeURL的另一个功能,带上JESSIONID访问即URL地址重写,会自动判断浏览器是是否支持的
//通过在其中包含会话ID对指定的URL进行编码,或者,如果不需要编码,则返回不变的URL
//之后服务器端会自动获取该ID
response.sendRedirect(response.encodeURL(url));

验证码

//getCode()获取验证码存入Session
request.getSession.setAttribute("code", getCode());

//然后和requset获取的对比
request.getParameter("code") == request.getSession.getAttribute("code")


10. Servlet访问流程,网络图来自java3y




API参考 oracle官网文档

Web.xml参考 思否







原文地址:https://www.cnblogs.com/Howlet/p/12038728.html