Servlet的使用_public appservlet(){super()}-程序员宅基地

技术标签: java  Servlet的使用  servlet  Javaweb  

Servlet

回顾
1、Tomcat的配置
2、Web项目结构
今日内容
1、Servlet概念和入门
2、Servlet获取请求参数
3、Servlet的生命周期
4、Servlet的两种创建方式
5、Servlet的两种配置方式
6、Servlet线程安全
教学目标
1、掌握Servlet的基本使用
2、了解Http协议
3、掌握Servlet获取请求参数
4、掌握Servlet的生命周期
5、掌握Servlet的两种创建方式
6、掌握Servlet的两种配置方式
7、掌握Servlet线程安全
第一节 Servlet概述
1.1 什么是Servlet
Servlet 是Java Server Applet的简称,称为小服务器程序,用Java编写的服务器端程序,主要功能交互式地浏览和修改数据,生成动态Web内容。
Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
Servlet编程需要使用到javax.servlet  和 javax.servlet.http两个包下面的类和接口,在所有的类和接口中,javax.servlet.Servlet 接口最为重要。所有的servlet程序都必须实现该接口或者继承实现了该接口的类。javax.servlet.ServletConfig;
javax.servlet.ServletException;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.http.HttpSession;
javax.servlet.http.Cookie;
1.2 Servlet入门
  1. 在src创建package

  2. 选中刚刚创建的包,右键–>New–>Servlet

  3. 第一个Servlet代码如下:

    /**
     *第一个Servlet程序
     */
    @WebServlet("/HelloServlet")
    public class HelloServlet extends HttpServlet {
          
    	private static final long serialVersionUID = 1L;
           
        /**
         * @see 构造函数
         */
        public HelloServlet() {
          
            super();
            // TODO Auto-generated constructor stub
        }
    
    	/**
    	 * @see 处理Get请求
    	 */
    	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          
    		// 响应内容到浏览器
    		response.getWriter().print("Hello Word");;
    	}
    
    	/**
    	 * @see 处理Post请求
    	 */
    	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          
    		// TODO Auto-generated method stub
    		doGet(request, response);
    	}
    
    }
    
  4. 发布右键–>Run As–>Run On Server

  5. 浏览器输入网址访问:http://localhost:8080/项目名称/HelloServlet

1.3 常见错误解决方法
HTTP Status 404   资源找不到
解决方法:查看Tomcat的webapps目录下找到当前项目在WEB-INF下的classes内能否找到刚刚的class文件
如果有,重新启动Tomcat
如果没有,在Eclipse中选择Project-->clean让Eclipse清空缓存并重新构建项目,再次运行
1.4 HTTP协议
1.4.1 什么是HTTP协议
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式。
HTTP协议的主要特点如下:
1.支持客户端/服务器模式。
2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
3.灵活:HTTP允许传输任意类型的数据对象。传输的类型由Content-Type加以标记。
4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
1.4.2 Http协议的通信
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤:
1、 建立TCP连接
在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同构建Internet,即著名的TCP/IP协议族,因此Internet又被称作是TCP/IP网络。HTTP是比TCP更高层次的应用层协议,根据规则,只有低层协议建立之后才能进行更低层协议的连接。因此,首先要建立TCP连接,一般TCP连接的端口号是80
2、 浏览器向Web服务器发送请求命令
一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令
例如:GET/sample/hello.html HTTP/1.1
3、 浏览器发送请求头信息
浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。
4、 Web服务器应答
客户机向服务器发出请求后,服务器会客户机回送应答,
HTTP/1.1 200 OK
应答的第一部分是协议的版本号和应答状态码
5、 Web服务器发送应答头信息
正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
6、 Web服务器向浏览器发送数据
Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据
7、 Web服务器关闭TCP连接
一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码
Connection:keep-alive
TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽
4.4.3 数据格式

HTTP请求格式

当浏览器向Web服务器发出请求时,它向服务器传递了一个数据块,也就是请求信息(请求报文),HTTP请求信息由4部分组成:
1 请求行 请求方法/地址 URI协议/版本
2 请求头(Request Header)
3 空行
4 请求正文
下面是一个HTTP请求的例子:
POST/hello HTTP/1.1
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language:zh-CN,zh;q=0.8,en-GB;q=0.6,en;q=0.4
Connection:Keep-Alive
Host:localhost:8080
User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Accept-Encoding:gzip, deflate, br

数据
1、请求方法URI协议/版本
请求的第一行是“方法URL议/版本”:GET/hello HTTP/1.1
以上代码中“GET”代表请求方法,“/hello”表示URI,“HTTP/1.1代表协议和协议的版本。
根据HTTP标准,HTTP请求可以使用多种请求方法。例如:HTTP1.1支持7种请求方法:GET、POST、HEAD、OPTIONS、PUT、DELETE和TARCE。在Internet应用中,最常用的方法是GET和POST。
URL完整地指定了要访问的网络资源,通常只要给出相对于服务器的根目录的相对目录即可,因此总是以“/”开头,最后,协议版本声明了通信过程中使用HTTP的版本。
2、请求头(Request Header)
请求头包含许多有关的客户端环境和请求正文的有用信息。例如,请求头可以声明浏览器所用的语言,请求正文的长度等。
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language:zh-CN,zh;q=0.8,en-GB;q=0.6,en;q=0.4
Connection:Keep-Alive
Host:localhost
User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Accept-Encoding:gzip, deflate, br
3  空行
4、请求正文
请求头和请求正文之间是一个空行,这个行非常重要,它表示请求头已经结束,接下来的是请求正文。请求正文中可以包含客户提交的查询字符串信息:
name=zhangsan
第二节 Servlet使用
2.1 Servlet核心接口和类
Servlet接口
在ServletAPI中最重要的是Servlet接口,所有Servlet都会直接或间接的与该接口发生联系,或是直接实现该接口,或间接继承自实现了该接口的类。
该接口包括以下五个方法:

init(ServletConfig config)
ServletConfig getServletConfig()
service(ServletRequest req,ServletResponse res)
String getServletInfo()
destroy( )


(1)第一次访问Servlet时,服务器会创建Servlet对象,并调用init方法,再调用service方法
(2)第二次再访问时,Servlet对象已经存在,不再创建,执行service方法
(3)当服务器停止,会释放Servlet,调用destroy方法。
GenericServlet抽象类
	GenericServlet 使编写 servlet 变得更容易。它提供生命周期方法 init 和 destroy 的简单实现,要编写一般的 servlet,只需重写抽象 service 方法即可。 
HttpServlet类
	是继承GenericServlet的基础上进一步的扩展。
	提供将要被子类化以创建适用于 Web 站点的 HTTP servlet 的抽象类。HttpServlet 的子类至少必须重写一个方法,该方法通常是以下这些方法之一: 
	doGet,如果 servlet 支持 HTTP GET 请求 
	doPost,用于 HTTP POST 请求 
	doPut,用于 HTTP PUT 请求 
	doDelete,用于 HTTP DELETE 请求 
	init 和 destroy,用于管理 servlet 的生命周期内保存的资源 
	getServletInfo,servlet 使用它提供有关其自身的信息 
2.2 Servlet的两种创建方式

Servlet的第一种创建方式:继承HttpServlet

/**
 * Servlet implementation class HelloServlet
 * 演示Servlet的第一种创建方式,继承HttpServlet.也是开发中推荐的
 * 
 */
@WebServlet("/hs1")
public class HelloServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		response.getWriter().print("我是Servlet创建的第一种方式");
	}
	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}
}

Servlet创建的第二种方式:实现接口Servlet

/**
 * Servlet创建的第二种方式:实现接口Servlet
 * */
@WebServlet("/hs2")
public class HelloServlet2 implements Servlet{

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
	}

	@Override
	public ServletConfig getServletConfig() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getServletInfo() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void init(ServletConfig arg0) throws ServletException {
		// TODO Auto-generated method stub	
	}
	@Override
	public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		System.out.println("OK");
		response.setContentType("text/html;charset=UTF-8");
		response.getWriter().println("我是第二种创建方式");
	}
}
2.3 Servlet的两种配置方式

第一种注解式配置 Servlet3.0及以后 :

/**
 * Servlet implementation class HelloServlet
 * 演示Servlet注解式配置
 */
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		response.getWriter().print("OK");
	}
	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}
}



使用注解方式:

value: 配置url路径

urlPatterns:配置url路径 ,和value作用一样,不能同时用

loadOnStartup:配置Servlet的创建的时机, 如果是0或者正数 启动程序时,则创建,如果是负数,则访问时创建

initParams:配置Servlet的初始化参数

第二种web.xml配置 Servlet所有版本都支持:

/**
 * Servlet implementation class HelloServlet
 * 演示Servlet的web.xml配置
 */
public class HelloServlet extends HttpServlet {
    
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
		
		response.getWriter().print("OK");
	}
	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
		// TODO Auto-generated method stub
		doGet(request, response);
	}
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
  <display-name>Web_Day11</display-name>
  <!--Servlet的第二种配置  -->
  <!--Servlet配置  -->
  <servlet>
  <!--名称  -->
    <servlet-name>hello2</servlet-name>
    <!--Servlet的全称类名  -->
    <servlet-class>com.qf.web.servlet.HelloServlet</servlet-class>
    <!--启动的优先级,数字越小越先起作用  -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <!--映射配置  -->
  <servlet-mapping>
  <!--名称  -->
    <servlet-name>hello2</servlet-name>
    <!--资源的匹配规则:精确匹配  -->
    <url-pattern>/hello2</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>login.html</welcome-file>
  </welcome-file-list>
</web-app>
容器在进行url-pattern配置的时候是遵循一定的匹配原则的
url-pattern定义匹配规则,取值说明:
精确匹配     /具体的名称		只有url路径是具体的名称的时候才会触发Servlet
后缀匹配     *.xxx			只要是以xxx结尾的就匹配触发Servlet
通配符匹配   /* 			    匹配所有请求,包含服务器的所有资源
通配符匹配   /                匹配所有请求,包含服务器的所有资源,不包括.jsp

load-on-startup 
1元素标记容器是否应该在web应用程序启动的时候就加载这个servlet。
2它的值必须是一个整数,表示servlet被加载的先后顺序。
3如果该元素的值为负数或者没有设置,则容器会当Servlet被请求时再加载。
4如果值为正整数或者0时,表示容器在应用启动时就加载并初始化这个servlet,值越小,servlet的优先级越高,就越先被加载。值相同时,容器就会自己选择顺序来加载。

<init-param>
      <param-name>name</param-name>
      <param-value>张三</param-value>
</init-param>
1 init-param元素用来定义Servlet启动的参数,可以定义多个
2 param-name表示参数名称
3 param-value表示参数值
2.4 Servlet生命周期
2.4.1 什么是生命周期
生命周期也就是生命历程,就像人都是从怀胎-->出生-->婴儿-->儿童-->少年-->成年-->中年-->老年-->死亡
2.4.2 生命周期的四个阶段
阶段一、实例化(调用构造方法)
实例化阶段是Servlet生命周期中的第一步,由Servlet容器调用Servlet的构造器创建一个具体的Servlet对象的过程。而这个创建的时机可以是在容器收到针对这个组件的请求之后,即用了才创建;也可以在容器启动之后立刻创建实例,而不管此时Servlet是否使用的上。使用如下代码可以设置Servlet是否在服务器启动时就执行创建
阶段二、初始化(init方法)
Servlet在被加载实例化之后,必须要初始化它。在初始化阶段,init()方法会被调用。这个方法在javax.servlet.Servlet接口中定义。其中,方法以一个ServletConfig类型的对象作为参数。ServletConfig对象由Servlet引擎负责创建,从中可以读取到事先在web.xml文件中通过<init-param>节点配置的多个name-value名值对。ServletConfig对象还可以让Servlet接受一个ServletContext对象。
一般情况下,init方法不需要编写,因GenericServlet已经提供了init方法的实现,并且提供了getServletConfig方法来获得ServletConfig对象。
注:init方法只被执行一次
阶段三、就绪/服务
Servlet被初始化以后就处于能够响应请求的就绪状态。每个对Servlet的请求由一个ServletRequest对象代表,Servlet给客户端的响应由一个ServletResponse对象代表。当客户端有一个请求时,容器就会将请求与响应对象转给Servlet,以参数的形式传给service方法。service方法由javax.servlet.Servlet定义,由具体的Servlet实现
HttpServlet将service方法拆分了。doGet和doPost
阶段四、销毁
Servlet容器在销毁Servlet对象时会调用destroy方法来释放资源。通常情况下Servlet容器停止或者重新启动都会引起销毁Servlet对象的动作,但除此之外,Servlet容器也有自身管理Servlet对象的准则,整个生命周期并不需要人为进行干预

Servlet代码如下:

/**
 * Servlet implementation class LifeServlet
 * 演示Servlet的生命周期:
 * 1、实例化
 * 2、init:初始化
 * 3、service:服务
 * 4、destory:销毁
 */
@WebServlet("/LifeServlet")
public class LifeServlet extends HttpServlet {
    
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public LifeServlet() {
    
        super();
        System.out.println("1、完成了实例化");
        // TODO Auto-generated constructor stub
    }
    @Override
    public void init() throws ServletException {
    
    	// TODO Auto-generated method stub
    	super.init();
    	System.out.println("2、完成了初始化");
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
		// TODO Auto-generated method stub
		System.out.println("3、就绪中");
		response.getWriter().append("Served at: ").append(request.getContextPath());
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
		// TODO Auto-generated method stub
		doGet(request, response);
	}
	
	@Override
	public void destroy() {
    
		// TODO Auto-generated method stub
		super.destroy();
		System.out.println("4、销毁了");
	}
}
2.5 获取请求参数

html页面:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>欢迎页面</title>
</head>
<body>
<h1>欢迎你</h1>
<div>
<form action="HelloServlet">
<label>姓名:</label><input name="name"><br/>
<label>年龄:</label><input  name="age"><br/>
<input type="submit" value="提交">
</form>
</div>
</body>
</html>

Servlet代码:


/**
 * Servlet implementation class HelloServlet
 * 演示Servlet的获取请求参数
 * 
 */
@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
    
	private static final long serialVersionUID = 1L;
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
		//获取表单提交的姓名
		String name=request.getParameter("name");
		//获取年龄
		String age=request.getParameter("age");
		//服务端输出打印
		System.out.println(request.getRemoteAddr()+"发来信息:姓名:"+name+"---->年龄:"+age);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
		// TODO Auto-generated method stub
		doGet(request, response);
	}
}
2.6 请求方式

默认的请求方式是GET请求

2.6.1 GET请求
GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连
GET提交的数据大小有限制(因为浏览器对URL的长度有限制)
GET方式提交数据,会带来安全问题
效率高

对应的Servlet的方法是doGet

2.6.2 POST请求
POST方法是把提交的数据放在HTTP包的Body中
POST方法提交的数据没有限制
POST提交的数据相对安全
效率相对没有GET高

对应的Servlet的方法是doPost

2.7 如何处理中文参数
2.7.1 为什么表单中会产生中文乱码
产生乱码,就是因为服务器和客户端沟通的编码不一致造成的,因此解决的办法是:在客户端和服务器之间设置一个统一的编码,之后就按照此编码进行数据的传输和接收
2.7.2 GET中文乱码
在Tomcat7及以下
客户端以UTF-8的编码传输数据到服务器端,而服务器端的request对象使用的是ISO8859-1这个字符编码来接收数据,服务器和客户端沟通的编码不一致因此才会产生中文乱码的。解决办法:在接收到数据后,先获取request对象以ISO8859-1字符编码接收到的原始数据的字节数组,然后通过字节数组以指定的编码构建字符串,解决乱码问题。

Tomcat8的版本中GET基本就不会乱码了,因为服务器对url的编码格式可以进行自动转换

解决get中文乱码的代码:

/**
 * Servlet implementation class HelloServlet
 * 演示Servlet的GET请求,中文乱码的问题
 * 
 */
@WebServlet("/GETServlet")
public class GetServlet extends HttpServlet {
    
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
		//获取表单提交的姓名
		String name=request.getParameter("name");
		name=new String(name.getBytes("ISO8859-1"),"UTF-8");
		//获取年龄
		String age=request.getParameter("age");
		//服务端输出打印
		System.out.println(request.getRemoteAddr()+"发来信息:姓名:"+name+"---->年龄:"+age);
	}
	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
		// TODO Auto-generated method stub
		doGet(request, response);
	}
}
2.7.3 POST乱码
由于客户端是以UTF-8字符编码将表单数据传输到服务器端的,因此服务器也需要设置以UTF-8字符编码进行接收,要想完成此操作,服务器可以直接使用从ServletRequest接口继承而来的"setCharacterEncoding(charset)"方法进行统一的编码设置。

解决POST中文乱码代码如下:

/**
 * Servlet implementation class HelloServlet
 * 演示Servlet的GET请求,中文乱码的问题
 * 
 */
@WebServlet("/GETServlet")
public class GetServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//设置请求参数的编码格式--对GET无效
        request.setCharacterEncoding("UTF-8");
		//获取表单提交的信息
		String name=request.getParameter("msg");
		//服务端输出打印
		System.out.println(request.getRemoteAddr()+"发来信息:"+msg);
	}
}
2.8 Servlet输出中文
2.8.1 页面返回乱码原因
浏览器识别不到返回的中文是什么编码格式,就会默认使用GB2312,如果返回的是UTF-8格式的那么在浏览器上就会显示乱码的问题
2.8.2 如何解决内容中的乱码
response.setContentType("text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");//输出一个完整的网页
2.9 Servlet线程安全问题
2.9.1 线程安全问题
因为每次请求都会创建一个线程,如果多人同时请求,那么就会存在多个线程操作同一个Servlet对象,那么如果在对应的方法中操作了成员变量,就有可能产生线程安全的问题。
2.9.2 如何保证线程安全
1、synchronized
将存在线程安全问题的代码放到同步代码块中
2、实现SingleThreadModel接口
servlet实现singleThreadModel接口后,每个线程都会创建servlet实例,这样每个客户端请求就不存在共享资源的问题,但是servlet响应客户端请求的效率太低,所以已经淘汰。
3、尽可能只使用局部变量
2.10 综合案例

实现注册信息的提交

页面:register.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户注册</title>
</head>
<body>
	<h1>用户注册</h1>
	<form action="/myxiaomi/registerservlet" method="post">
	<table>
		<tr>
			<td>用户名:</td>
			<td>
				<input type="text" name="username">
			</td>
		
		</tr>
		<tr>
			<td>密码:</td>
			<td>
				<input type="password" name="pwd">
			</td>
		
		</tr>
		<tr>
			<td>确认密码:</td>
			<td>
				<input type="password" name="repwd">
			</td>
		
		</tr>
		<tr>
			<td>邮箱:</td>
			<td>
				<input type="email" name="email">
			</td>
		
		</tr>
		<tr>
			<td>性别</td>
			<td>
				<input type="radio" name="gender" value="男" checked="checked">男
				<input type="radio" name="gender" value="女">女
			</td>
		
		</tr>
		<tr>
			
			<td colspan="2">
				<input type="submit" value="提交">
				<input type="reset" value="重置">
			</td>
		
		</tr>
	</table>
	
	</form>
</body>
</html>

Servlet:

RegisterServlet.java

package com.qf.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.tomcat.util.codec.binary.StringUtils;

import com.qf.utils.ActiveCodeUtils;





@WebServlet("/registerservlet")
public class RegisterServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
 
    public RegisterServlet() {
        super();
        // TODO Auto-generated constructor stub
    }


	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//注册
		//1编码
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		//2获取数据
		String username=request.getParameter("username");
		String pwd=request.getParameter("pwd");
		String repwd=request.getParameter("repwd");
		String email=request.getParameter("email");
		String gender=request.getParameter("gender");
		//3验证数据
		PrintWriter out = response.getWriter();
		if(username==null||username.trim().equals("")) {
			out.write("用户不能为空");
			return;
		}
		if(pwd==null||pwd.trim().equals("")) {
			out.write("密码不能为空");
			return;
		}
		if(!pwd.equals(repwd)) {
			out.write("两次密码不一样");
			return;
		}
		//4保存数据库
		Connection connection=null;
		PreparedStatement pstat=null;
		try {
			//4.1注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			//4.2获取连接
			connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/db_shopping", "root", "root");
			//4.3创建命令
			pstat=connection.prepareStatement("insert into tb_user(username,password,email,gender,flag,role,code) values(?,?,?,?,?,?,?)");
			//4.4设置参数
			pstat.setString(1, username);
			pstat.setString(2, pwd);
			pstat.setString(3, email);
			pstat.setString(4, gender);
			pstat.setInt(5, 0);
			pstat.setInt(6, 1);
			pstat.setString(7, ActiveCodeUtils.createActiveCode());
			//5执行
			int result=pstat.executeUpdate();
			if(result>0) {
				out.write("注册成功");
			}else {
				out.write("注册失败");
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			out.write("注册失败");
		}finally {
			if(connection!=null) {
				try {
					connection.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(pstat!=null) {
				try {
					pstat.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		
		
		
		
	}

	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		doGet(request, response);
	}

}

ActiveCodeUtils.java

package com.qf.utils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

/**
 * 激活码工具类
 * @author wgy
 *
 */
public class ActiveCodeUtils {
	public static String createActiveCode() {
		Date date=new Date();
		SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmssSSS");
		String s1=sdf.format(date);
		String s2=Integer.toHexString(new Random().nextInt(900)+100);
		return s1+s2;
	}
}
总结

1 什么是Servlet:小服务器程序,用Java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容。

2 创建Servlet

3 配置Servlet

4 接受请求参数

5 响应数据

作业题
1、请结合之前学习的前端技术,实现一个页面输入内容存储到数据库的功能
要求页面尽可能的包含自己会的标签,使用Servlet接收页面数据,通过JDBC存储到数据库
面试题
1、说一说Servlet生命周期
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_39513430/article/details/103546654

智能推荐

tensorflow解决gpu随机性问题,可复现_ttensorflow训练随机性固定-程序员宅基地

文章浏览阅读2.2k次,点赞2次,收藏15次。最近在准备小论文的实验,因为是做对比实验,但是由于存在随机性,在tensorflow框架中每次运行的结果都不一样,导致我改进的方法不知道是由于随机性造成的还是真的起到了作用,越来越怀疑,于是到处搜,怎么消除网络的随机性,终于在今天解决了这个问题,接下来可以放心调参了。首先所有的初始化要设置随机种子,在网络训练最前面加上以下代码,消除参数初始化带来的随机性,如果你的程序中用到了dropout也是需要设置seed的。然而单单设置上面的,每次运行的结果还是不一样,于是又苦逼的搜了很久,有的地方看到是因_ttensorflow训练随机性固定

Java- Stack与LinkedList实现。_java stack linkedlist-程序员宅基地

文章浏览阅读8.2k次,点赞7次,收藏7次。我们都知道栈有两种实现方式。一个用Stack类。一个用LinkedList类实现。那么它们之间有什么不同呢?我们先用一段代码显示一下。public static LinkedList&lt;String&gt; stack;public static Stack&lt;String&gt; stack1;public static LinkedList&lt;String&gt;..._java stack linkedlist

sql注入_qq机器人sql注入-程序员宅基地

文章浏览阅读183次。用SQL(结构化查询语言)对SQL数据库(大多数Web应用都使用SQL数据库来存放应用程序的数据)进行“增删改查”。一、可SQL注入的原因1.允许数据库命令和用户数据混杂在一起的。远程用户不仅能向Web应用输入数据,而且还可以在数据库上执行任意命令,SQL注入使攻击者绕过认证机制,损害数据库的内容。2.动态生成Sql语句时没有对用户输入的数据进行判断是Sql注入攻击得逞的主要原因二、SQL..._qq机器人sql注入

Vue中数据截取换行显示(v-html用法)_el-table 内容使用v-html显示换行-程序员宅基地

文章浏览阅读2.7k次。_1.Vue表格内容数据显示_1 <el-table-column label="详细" min-width="200">2 <template slot-scope="scope">3 <span v-html="**cutout(scope.row.log\_op\_detail)"**/>(取到字段里对应的内容,调用cutout方法)v-html会将其中html标签解析后输出。4 &_el-table 内容使用v-html显示换行

1-1HTML笔记总结_lom/eqtf8lunpi6lr+njig==-程序员宅基地

文章浏览阅读269次。文章目录HTML概述互联网原理互联网运行过程客户端主流浏览器及其内核浏览器功能HTTP请求与HTTP响应HTML概念纯文本文件的特点语义化网页的优势HTML规范版本vscode常用快捷键HTML基本结构DTD常见字符集编码标题标签h1-h6段落标签p换行标签br文本格式化图像标签imgimg标签属性相对路径同级查找子级查找上级查找绝对路径盘符出发网址形式音频标签audio视频标签video超级链接ahref属性target属性title属性页面内锚点跳转跨页面锚点跳转无序列表ul>li有序列表ol&g_lom/eqtf8lunpi6lr+njig==

GitHub 热榜:这款开源神器可帮您将文本转换为手写文字,并下载为 PDF 格式文件!...-程序员宅基地

文章浏览阅读1.8k次。今天给大家推荐一个非常有意思的开源工具 —— Text-to-handwriting。该开源工具是一名来自印度塔内的大学生 Saurabh Daware 开源,他花费了 3 个小时编写了..._开源手写字

随便推点

sql练习-程序员宅基地

文章浏览阅读167次。本次练习文章从创建表——>往表中插入数据——>查询 、修改、删除表数据use master; --使用系统数据库create database anqier; -- 创建数据库anqierselect *from emp; --查询emp表中的所有数据drop table emp; --删除这个表的数据,并且删除了表本身。truncate table emp ..._sql王小五例题

瑞星微 AI情况简介_瑞星微量化方式-程序员宅基地

文章浏览阅读673次。5月21日,福州瑞芯微电子Rockchip(以下简称瑞芯微)宣布旗下AI平台重大升级,正式面向全球AI开发者发布三大开发套件:AI开发工具包RKNN-Toolkit、AI SDK软件开发工具包Rock-X SDK,以及AI人工智能计算棒RK1808 AI Compute Stick。开发工具包与软件工具包主要适配于带有硬件NPU加速器的瑞芯微RK3399Pro/RK1808芯片平台,不仅能增强..._瑞星微量化方式

LaTeX 入门 01_使用latex文字跟随在小标题后面,怎么独立一行-程序员宅基地

文章浏览阅读287次。实现中英文混排方法一\documentclass[UTF8]{ctexart} % 实现中英文混排 : ctex 宏包 % 文档类{},文档类选项[]\begin{document} Hello, \LaTeX ! 你好,\LaTeX !\end{document}编译后输出如下方法二\documentclass{article}\usepackage{xeCJK} % 调用 xeCJK 宏包\setCJKmainfont{SimSun} _使用latex文字跟随在小标题后面,怎么独立一行

TeamCity VS Jenkins:选择正确的CI / CD工具-程序员宅基地

文章浏览阅读1.6w次。每个软件开发周期都涉及三个主要阶段:构建,测试和部署。这三个阶段中的任何一个滞后都会导致产品发布的延迟。为了避免此类延迟,组织依靠CI / CD工具来自动化这些过程。但是最近,随着对CI..._teamcity和jenkins

2019eclipse 中文汉化包 安装教程_eclipse2019汉化包安装教程-程序员宅基地

文章浏览阅读5.8k次,点赞3次,收藏8次。用的是官方的汉化包 首先查询你的 eclipse 的版本 号 :打开eclipse文件位置 -->打开Readme文件夹 ,点击里面的文件,然后如下图,例如我的eclipse版本是:Release 4.8.0 版本 ,后面有一个“Photon”。 找到你的版本之后,打开这个网址:http://www.eclipse.org..._eclipse2019汉化包安装教程

java用画线写字_用Java画线-程序员宅基地

文章浏览阅读127次。我已经尝试过使用此代码画一条线,并且效果很好.import java.awt.*;import javax.swing.*;public class New extends JFrame {public New() {setSize(960, 960);setVisible(true);setDefaultCloseOperation(EXIT_ON_CLOSE);}public void pai..._java使用横杠生成文字

推荐文章

热门文章

相关标签