深入理解Servlet

虾米姐 阅读:646 2021-03-31 14:15:05 评论:0

第一:动态资源与静态资源的区别:

静态资源: 当用户多次访问这个资源,资源的源代码永远不会改变的资源。
动态资源:当用户多次访问这个资源,资源的源代码可能会发送改变

第二:Servlet

2.1 什么是Servlet

使用java语言来编写动态Web的开发技术。

2.2 Servlet 开发流程

1、继承HttpServlet类,覆写doGet\doPost等相关方法。
2、自定义HttpServ类写入Web.xml 文件中。

2.3 Servlet 开发实例(基于SpringBoot 基础环境开发)

package com.zzg.eshop.servlet; 
 
import java.io.IOException; 
import java.util.Date; 
 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
 
@SuppressWarnings("serial") 
public class HelloServlet extends HttpServlet { 
 
	@Override 
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
		//解决中文乱码问题 
	    resp.setCharacterEncoding("utf-8");// 内容编码,防止出现中文乱码 
		resp.setContentType("text/html;charset=utf-8");		//向浏览器输出内容 
		resp.getWriter().write("这是第一个servlet程序。当前时间为:"+new Date()); 
	} 
 
	@Override 
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
		// TODO Auto-generated method stub 
		this.doGet(req, resp); 
	} 
 
	 
} 
 
 
package com.zzg.eshop.config; 
 
import org.springframework.boot.web.servlet.ServletRegistrationBean; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
 
import com.zzg.eshop.servlet.HelloServlet; 
 
/** 
 * servlet 配置类 
 * @author Administrator 
 * 
 */ 
@Configuration 
public class ServletInitConfig { 
	 // 注册servlet 
    @Bean 
    public ServletRegistrationBean hello(){ 
      //第一个参数是第1步中创建的WeChatServlet实例,第二个参数是其对应的路径,相当于web.xml中配置时的url-pattern。 
      return new ServletRegistrationBean(new HelloServlet(), "/hello"); 
    } 
} 
 
 
package com.zzg.eshop; 
 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.boot.builder.SpringApplicationBuilder; 
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 
 
@SpringBootApplication 
public class Application extends SpringBootServletInitializer  { 
 
	public static void main(String[] args) { 
		// TODO Auto-generated method stub 
		 SpringApplication.run(Application.class, args); 
	} 
 
	@Override 
	protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { 
		// TODO Auto-generated method stub 
		return builder.sources(Application.class); 
	} 
	 
	 
	 
	 
 
} 

2.4 Servlet 开发实例(SpringBoot 开发环境注解版本)

package com.zzg.eshop; 
 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.boot.builder.SpringApplicationBuilder; 
import org.springframework.boot.web.servlet.ServletComponentScan; 
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 
 
@SpringBootApplication 
@ServletComponentScan 
public class Application extends SpringBootServletInitializer  { 
 
	public static void main(String[] args) { 
		// TODO Auto-generated method stub 
		 SpringApplication.run(Application.class, args); 
	} 
 
	@Override 
	protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { 
		// TODO Auto-generated method stub 
		return builder.sources(Application.class); 
	} 
	 
	 
	 
	 
 
} 
 
 
package com.zzg.eshop.servlet; 
 
import java.io.IOException; 
import java.util.Date; 
 
import javax.servlet.ServletException; 
import javax.servlet.annotation.WebServlet; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
 
@SuppressWarnings("serial") 
@WebServlet(urlPatterns = "/annotation", description = "servlet 注解版本") 
public class AnnotationServlet extends HttpServlet { 
 
	@Override 
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
		// TODO Auto-generated method stub 
		//解决中文乱码问题 
	    resp.setCharacterEncoding("utf-8");// 内容编码,防止出现中文乱码 
		resp.setContentType("text/html;charset=utf-8");		//向浏览器输出内容 
		resp.getWriter().write("servlet注解版本程序。当前时间为:"+new Date()); 
	} 
 
	@Override 
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
		// TODO Auto-generated method stub 
		this.doGet(req, resp); 
	} 
	 
}	 

2.4 Servlet 生命周期:

servlet类对象什么时候创建,什么时候调用什么方法,什么时候销毁。由tomcat服务器控制

2.5 Servlet 生命周期重要的四个方法:

2.5.1 四个方法详解:

构造方法: 创建servlet对象的时候调用。默认情况下,第一次访问servlet的时候创建servlet对象 ,只调用1次。证明servlet对象在tomcat是单实例的。
init方法: 创建完servlet对象的时候调用。只调用1次。
service方法: 每次发出请求时调用。调用n次。

destroy方法: 销毁servlet对象的时候调用。停止服务器或者重新部署web应用时销毁servlet对象。只调用1次。

2.5.2 伪代码演示Servlet 的生命周期

Tomtcat内部代码运行: 
			1)通过映射找到到servlet-class的内容,字符串: com.zzg.eshop.servlet.HelloServlet 
			2)通过反射构造FirstServlet对象 
					2.1 得到字节码对象 
					Class clazz = class.forName("com.zzg.eshop.servlet.HelloServlet"); 
					2.2 调用无参数的构造方法来构造对象 
					Object obj = clazz.newInstance();     ---1.servlet的构造方法被调用 
			3)创建ServletConfig对象,通过反射调用init方法 
					3.1 得到方法对象 
					Method m = clazz.getDeclareMethod("init",ServletConfig.class); 
					3.2 调用方法 
					m.invoke(obj,config);             --2.servlet的init方法被调用 
			4)创建request,response对象,通过反射调用service方法 
					4.1 得到方法对象 
					Methodm m =clazz.getDeclareMethod("service",HttpServletRequest.class,HttpServletResponse.class); 
					4.2 调用方法 
					m.invoke(obj,request,response);  --3.servlet的service方法被调用 
			5)当tomcat服务器停止或web应用重新部署,通过反射调用destroy方法 
					5.1 得到方法对象 
					Method m = clazz.getDeclareMethod("destroy",null); 
					5.2 调用方法 
					m.invoke(obj,null);            --4.servlet的destroy方法被调用

2.5.3 时序图演示Servlet 的生命周期

2.6 Servlet 优先级设置

2.6.1 Springboot 代码版:在Servlet 注册对象ServletRegistrationBean中调用setLoadOnStartup方法,设置Servlet 的优先级。

package com.zzg.eshop.config; 
 
import org.springframework.boot.web.servlet.ServletRegistrationBean; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
 
import com.zzg.eshop.servlet.HelloServlet; 
 
/** 
 * servlet 配置类 
 * @author Administrator 
 * 
 */ 
@Configuration 
public class ServletInitConfig { 
	 // 注册servlet 
    @Bean 
    public ServletRegistrationBean hello(){ 
      //第一个参数是第1步中创建的WeChatServlet实例,第二个参数是其对应的路径,相当于web.xml中配置时的url-pattern。 
    	ServletRegistrationBean bean = new ServletRegistrationBean(new HelloServlet(), "/hello"); 
    	// 优先级设置,注意:整数值越大,创建优先级越低 
    	bean.setLoadOnStartup(1); 
      return bean; 
    } 
} 

2.6.2 Springboot 注解版:在Servlet 注解对象@WebServlet标签中设置loadOnStartup属性,实现Servlet 的优先级的设置。

package com.zzg.eshop.servlet; 
 
import java.io.IOException; 
import java.util.Date; 
 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.annotation.WebServlet; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
 
@SuppressWarnings("serial") 
@WebServlet(urlPatterns = "/annotation", description = "servlet 注解版本", loadOnStartup = 2) 
public class AnnotationServlet extends HttpServlet { 
	 
	 
 
	@Override 
	public void init() throws ServletException { 
		// TODO Auto-generated method stub 
		super.init(); 
		System.out.println("-----------AnnotationServlet启动" + new Date()); 
	} 
 
 
	@Override 
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
		// TODO Auto-generated method stub 
		//解决中文乱码问题 
	    resp.setCharacterEncoding("utf-8");// 内容编码,防止出现中文乱码 
		resp.setContentType("text/html;charset=utf-8");		//向浏览器输出内容 
		resp.getWriter().write("servlet注解版本程序。当前时间为:"+new Date()); 
	} 
 
	@Override 
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
		// TODO Auto-generated method stub 
		this.doGet(req, resp); 
	} 
	 
}	 

2.7 Servlet的多线程并发问题

       因为servlet是多线程的,所以当多个servlet的线程同时访问了servlet的共享数据,如成员变量,可能会引发线程安全问题。

       解决办法:

                     1)把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步)
                     2)建议在servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步。而且尽量缩小同步代码块的范围。(哪里使用到了成员变量,就同步哪里!!),以避免因为同步而导致并发效率降低。

实例:多线程不安全Servlet

package com.zzg.eshop.servlet; 
 
import java.io.IOException; 
 
import javax.servlet.ServletException; 
import javax.servlet.annotation.WebServlet; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
 
@SuppressWarnings("serial") 
@WebServlet(urlPatterns = "/unsafe", description = "servlet 线程不安全") 
public class ThreadUnSafeServlet extends HttpServlet { 
	private int i = 1; 
 
	@Override 
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
		// TODO Auto-generated method stub 
		// 设置编码格式 
		// resp.setContentType("text/html;charset=utf-8"); 
		resp.setCharacterEncoding("utf-8");// 内容编码,防止出现中文乱码 
		resp.setContentType("text/html;charset=utf-8"); 
		 
			// 向浏览器输出内容 
			resp.getWriter().write("这是第" + i + "次访问..."); 
			try { 
				Thread.sleep(5000); 
			} catch (Exception e) { 
				// TODO: handle exception 
			} 
 
			i++; 
 
	} 
 
	@Override 
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
		// TODO Auto-generated method stub 
		this.doGet(req, resp); 
	} 
 
} 

实例:多线程安全Servlet

package com.zzg.eshop.servlet; 
 
import java.io.IOException; 
 
import javax.servlet.ServletException; 
import javax.servlet.annotation.WebServlet; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
 
@SuppressWarnings("serial") 
@WebServlet(urlPatterns = "/safe", description = "servlet 线程安全") 
public class ThreadSafeServlet extends HttpServlet { 
	private int i = 1; 
 
	@Override 
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
		// TODO Auto-generated method stub 
		// 设置编码格式 
		// resp.setContentType("text/html;charset=utf-8"); 
		resp.setCharacterEncoding("utf-8");// 内容编码,防止出现中文乱码 
		resp.setContentType("text/html;charset=utf-8"); 
		synchronized (ThreadSafeServlet.class) { 
			// 向浏览器输出内容 
			resp.getWriter().write("这是第" + i + "次访问..."); 
			try { 
				Thread.sleep(5000); 
			} catch (Exception e) { 
				// TODO: handle exception 
			} 
			 
			i++; 
		} 
 
	} 
 
	@Override 
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
		// TODO Auto-generated method stub 
		this.doGet(req, resp); 
	} 
 
} 

2.8 ServletContext对象

1、获取Web应用路径

2、用于保存数据,获取数据。可以在不同的Servlet之间共享数据。

实例代码:

package com.zzg.eshop.servlet; 
 
import java.io.IOException; 
 
import javax.servlet.ServletContext; 
import javax.servlet.ServletException; 
import javax.servlet.annotation.WebServlet; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
 
@SuppressWarnings("serial") 
@WebServlet(urlPatterns = "/context", description = "ServletContext 功能演示") 
public class ContextServlet extends HttpServlet { 
 
	@Override 
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
		// TODO Auto-generated method stub 
		ServletContext context = this.getServletConfig().getServletContext(); 
		// 输出web应用路径 
		System.out.println("应用路径" + context.getContextPath()); 
		 
		// 域对象保存数据 
		context.setAttribute("uuid", System.currentTimeMillis()); 
		 
		// 域对象获取数据 
		long uuid = (long) context.getAttribute("uuid"); 
		System.out.println("uuid" + uuid); 
	} 
 
	@Override 
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
		// TODO Auto-generated method stub 
		this.doGet(req, resp); 
	} 
	 
	 
 
} 

2.9 转发和重定向

2.9.1 转发

 1)地址栏不会改变
 2)转发只能转发到当前web应用内的资源
 3)可以在转发过程中,可以把数据保存到request域对象中

2.9.2 重定向

1)地址栏会改变,变成重定向到地址。
2)重定向可以跳转到当前web应用,或其他web应用,甚至是外部域名网站。

 3)不能再重定向的过程,把数据保存到request中。

 

标签:Servlet
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号