mapengpeng1999@163.com Servlet相关知识

1.Servlet简介

Servlet就是一个使用Java程序实现的Web操作,和JSP没有任何本质的区别,都是使用浏览器进行访问,
JSP实际上就是一个Servlet程序,因为JSP会被web容器动态拼凑成Servlet程序,并且进行编译,
但是JSP中编写Java代码需要以scriptlet的形式呈现,导致整个JSP的可读性和可维护性很低,
Servlet的处理流程和Jsp的处理流程差不多,但是少了一个拼凑代码的过程。
而Servlet本身就是一个类,所以里面可以编写任意多的Java代码,
但是Servlet如果要进行显示的话,比较困难,因为必须使用out.print()一行一行的向页面输出,
所以我们的开发后期就是要结合JSP和Servlet各自的优势。JSP和Servlet是可以相互跳转的。
Servlet叫做服务端小程序,是sun公司最早推出的动态web的实现方式,
使用Java语言编写,在程序中使用out.print()一行一行的输出html代码,非常复杂,既然是动态web的实现,和jsp一样,都是通过浏览器访问。
Servlet的处理流程:
- 浏览器通过发送HTTP请求,请求访问一个地址
- 这个地址如果是Servlet配置的映射地址,Web容器就会将请求发给Servlet
- 如果这个Servlet之前没有被访问过,则进行初始化,
Web服务器也会将Servlet加载到Java虚拟机并运行,否则跳过此步骤
- Servlet程序接收HTTP请求并且执行这个请求
- Servlet将处理的结果响应给浏览器进行显示

Servlet程序的基本实现:
在整个Servlet程序中,最重要的就是Servlet接口,此接口定义了一个GenericServlet实现类,
但是在开发中,我们一般不会去继承这个类,而是根据所使用的网络协议选择此类的子类,
例如现在使用的是Http协议,所以我们一般使用采用HTTP协议操作的子类,叫做HttpServlet。

Servlet开发要求:
- 必须继承HttpServlet或者其更高继承关系的父类或者父接口,这样的程序才叫做Servlet程序,
正常开发中,我们一般使用继承HttpServlet类完成。
- Servlet程序必须放在一个包中
- Servlet必须要复写HttpServlet类中服务的方法(doGet 和 doPost)
- Servlet程序本身是通过浏览器访问的,所以不需要main方法

2.需求:通过运行Servlet程序,在页面显示HelloWorld

对于Servlet开发要求来说,第1,2,4我们都很清楚,关键是第三点,Servlet常用的服务的方法有哪些呢?
- doGet:处理get请求
- doPost:处理post请求
- doDelete:处理delete请求【SpringMVC再讲解】
- doPut:处理put请求【SpringMVC再讲解】
- service : 处理所有请求【在Servlet生命周期中讲解】
只用复写一个方法就行了
像创建类那样new个Servlet,next, Add URL mappings可增加映射地址,再next勾上do set和do post方法(将servlet放到一个包中)

复制全类名:右击类名,选择Coyp Qualified name就复制好全类名了。
查看类的源代码,Ctrl+鼠标左击
package com.wanbang.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServletDemo01 extends HttpServlet {

	/**
	 * 	 在JavaWeb中,一般来说,要么是get请求,要么是post请求,
	 而且同一个操作,无论是get还是post请求,处理过程一般一致的,只用复写一个方法就行了
	 */
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	//获得out对象之前要进行设置
		//响应的设置MIME类型
		response.setContentType("text/html;charset=utf-8");
		//设置输出响应内容的字符集
		response.setCharacterEncoding("utf-8");
		
		PrintWriter out = response.getWriter();//获取out对象
		out.print("<html>");//使用out.print();向页面输出内容
		out.print("<body>");
		out.print("<h1>Hello World</h1>");
		out.print("</body>");
		out.print("</html>");
		out.close();//输出内容结束,响应完成
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doGet(request, response);
	}
}
代码编写好了,但是要通过浏览器访问,怎么处理呢?有两种方式:
- 通过配置文件,在web.xml中配置这个Servlet映射地址
- 通过注解完成Servlet地址映射。第二种最常用。

注解路径配置ok,都正常的操作了还不能访问,就去tomcat里看这个类有没有编译成功,
tomcat,wtpwebapps,项目中,WEB-INF的classes里没有class字节码文件就说明没编译,就在eclipse中project,clean清除下所有缓存,在eclipse中设置自动编译,project,勾上Build Automatically就好了
第一种方式:
<!-- 
 	一个Servlet可以配置多个映射地址,但是一个映射地址不可以配置到多个Servlet上
  -->
 <servlet>
 	<servlet-name>ServletDemo01</servlet-name>
 	<servlet-class>com.wanbang.servlet.ServletDemo01</servlet-class>
 </servlet>
 <servlet-mapping>
 	<servlet-name>ServletDemo01</servlet-name>
 	<url-pattern>/abc</url-pattern>
 </servlet-mapping>
第二种方式:使用注解的方式(以后开发都用这个)

@WebServlet("/abc")  //如果注解中的属性只配置value的话,则可以省略value
//@WebServlet(value="/abc")  //映射一个URL地址

//@WebServlet(urlPatterns= {"/123","/321"}) //通过注解给Servlet映射多个URL地址,用集合形式,一般一个servlet只配置一个URL映射

3.Servlet与jsp

JSP本质就是一个Servlet程序,都是以浏览器的形式访问的,所以JSP中的表单是可以直接提交到Servlet中的。
一个jsp可通过表单提交,a标签,jsp:forward,response.sendRedirect()等方式跳转到一个Servlet程序。
	<form action="<%= request.getContextPath() %>/ServletDemo01" method="get">
		账户ID:<input type="text" name="accId">
		账户名:<input type="text" name="accName">
		密码:<input type="password" name="accPass">
		充值金额:<input type="text" name="accBalance">
		<input type="submit" value="提交">
	</form>
	
	@WebServlet("/ServletDemo01")
public class ServletDemo01 extends HttpServlet {
	private static final long serialVersionUID = 1L;
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		Integer accId = Integer.parseInt(request.getParameter("accId"));
		String accName = request.getParameter("accName");
		String accPass = request.getParameter("accPass");
		Double accBalance = Double.parseDouble(request.getParameter("accBalance"));
		
		System.out.println(accId);
		System.out.println(accName);
		System.out.println(accPass);
		System.out.println(accBalance);
		//控制台能输出结果就行
	}
}

修改登录程序:(登录提交到一个Servlet程序进行登录验证,而非Jsp)

数据库连接工具类:
package com.wanbang.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class DBConnection {
	public static final String MYSQLDRIVER = "com.mysql.jdbc.Driver";
	public static final String MYSQLURL = "jdbc:mysql:///javaweb";
	public static final String MYSQLUSER = "root";
	public static final String MYSQLPASS = "3306";
	public static Connection getMySQLConnection() throws Exception{
		Class.forName(MYSQLDRIVER);
		Connection conn = DriverManager.getConnection(MYSQLURL, MYSQLUSER, MYSQLPASS);
		return conn;
	}
	
	public static void closeMySQL(Connection conn,PreparedStatement state,ResultSet res)throws Exception {
		if(null != conn) {
			conn.close();
		}
		if(null != state) {
			state.close();
		}
		if(null != res) {
			res.close();
		}
	}
}
JSP登录表单:
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="<%= request.getContextPath() %>/LoginServlet" method="post">
		<table>
			<caption>登录</caption>
			<tr>
				<td align="right">用户名:</td>
				<td align="left"><input type="text" name="userName" ></td>
			</tr>
			<tr>
				<td align="right">密码:</td>
				<td align="left"><input type="password" name="passWord"></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<input type="submit" value="登录"/>
					<input type="reset" value="重置"/>
				</td>
			</tr>
		</table>
	</form>
</body>
</html>
Servlet验证:
package com.wanbang.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
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 com.wanbang.util.DBConnection;

@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	
		response.setContentType("text/html;charset = utf-8");
		response.setCharacterEncoding("UTF-8");
		PrintWriter out = response.getWriter();
		
		request.setCharacterEncoding("utf-8");
		String userName = request.getParameter("userName");
		String passWord = request.getParameter("passWord");
		Connection conn = null;
		PreparedStatement pstate = null;
		ResultSet res = null;
		boolean flag = false;
		String realName = null;
		try {
			conn = DBConnection.getMySQLConnection();
			String sql = "select user_id,real_name from user_info where user_name = ? and pass_word = ?";
			pstate = conn.prepareStatement(sql);
			pstate.setString(1,userName);
			pstate.setString(2,passWord);
			res = pstate.executeQuery();
			while(res.next()){
				realName = res.getString(2);
				flag = true;
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				DBConnection.closeMySQL(conn, pstate, res);
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		}
		if(flag) {
			out.print("登录成功,欢迎您:" + realName);
			
		}else {
			out.print("登录失败");
		}
		out.close();
		
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	// TODO Auto-generated method stub
		doGet(request, response);
	}
}

2.4 Servlet中取得初始化参数

通过config对象获得初始化配置的参数,而且这个参数是在web.xml文件中配置的,而后在jsp中获取的,
对于Servlet来说,初始化参数的配置依然使用config对象,而初始化参数的配置有两种:
- 和之前在web.xml中的配置一样
- 使用注解配置
第一种方式:
<servlet>
  	<servlet-name>ServletDemo02</servlet-name>
  	<servlet-class>com.wanbangee.servlet.ServletDemo02</servlet-class>
  	<init-param>
      <param-name>name</param-name>
      <param-value>姜建民</param-value>
    </init-param>
    <init-param>
      <param-name>add</param-name>
      <param-value>福建省厦门市思明区莲前街道软件园二期观日路54号A座501</param-value>
    </init-param>
    <init-param>
      <param-name>ress</param-name>
      <param-value>福建省厦门市思明区莲前街道软件园二期望海路2号</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
  	<servlet-name>ServletDemo02</servlet-name>
  	<url-pattern>/SevletDemo02</url-pattern>
  </servlet-mapping>
  
 第二种配置方式:
//配置url映射地址,及初始化参数
@WebServlet(value="/ServletDemo02",initParams= {@WebInitParam(name="com",value="万邦易嵌"),@WebInitParam(name="add",value="黄家湖")})
在Servlet中获得配置的初始化参数:

@WebServlet(value="/ServletDemo01",initParams= {@WebInitParam(name="com",value="万邦易嵌"),@WebInitParam(name="add",value="黄家湖")})
public class ServletDemo01 extends HttpServlet {
private static final long serialVersionUID = 1L;
	
	private String com;
	private String add;
	//Servlet初始化方法 : 普通的
	@Override
	public void init() throws ServletException {
		super.init();
	}

	//Servlet初始化方法 :可以接受初始化参数的
	@Override
	public void init(ServletConfig config) throws ServletException {
		System.out.println("Servlet初始化的方法");
		com = config.getInitParameter("com");
		add = config.getInitParameter("add");
	}

	//处理get请求
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println(com);
		System.out.println(add);
	}

	//处理post请求
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doGet(request, response);
	}
}

2.5 在Servlet中获取其他的常用对象

在Servlet中已经操作过这四个对象:out,config,request,response,
要关注的就是剩下的常用的对象了:
- session
- application
- pageContext
- 获取session对象:在HttpServletRequest接口中,存在两个方法
- HttpSession getSession() : 获取当前的session对象
- HttpSession getSession(boolean create):获取当前的session对象,如果参数值为true,则表示如果session不存在,则创建session,存在则直接获取,如果参数值为false,则和第一个方法相同。

- 获得application对象:跟我们之前获取的方式一样,application对象是ServletContext接口的对象,主要功能就是获得虚拟目录的真实路径,现在一般使用getServletContext()方法,这个方法的返回值就是application对象。
		
- 获得pageContext对象,这个对象取得比较复杂, 但是实际开发中使用也比较少,我们后面有个地方,使用smartupload上传文件的时候需要使用。
@WebServlet("/ServletDemo01")
public class ServletDemo01 extends HttpServlet {
	private static final long serialVersionUID = 1L;
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		HttpSession session = request.getSession();//获得session对象
		
		System.out.println(session.getAttribute("test"));
		System.out.println(session.getId());
		//打印JSESSIONID值
		ServletContext application = this.getServletContext(); //获得application对象
		application = request.getServletContext();//获得application对象
		application = session.getServletContext();//获得application对象
		System.out.println(application.getRealPath("/"));
		//获得虚拟目录的真实路径,就是项目在硬盘中的真实路径
		
		JspFactory factory = JspFactory.getDefaultFactory();//获得Jsp工厂对象
		//获得pageContext对象
		PageContext pageContext = factory.getPageContext(this, request, response, null, false, 0, false);
	}

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

打印结果为:
null
38529DD74C90EABE52A4498A0FF4CBD1
D:\Tomcat\apache-tomcat-8.5.55\wtpwebapps\Web\

2.6 Servlet跳转

一个JSP可以轻松的跳转到Servlet,比如表单提交,超链接,重写地址栏,jsp:forward,respons.sendRedirect()等等方式,那么Servlet如何跳转到jsp呢?其实和之前也是一样,只是是通过Java代码完成。我们知道跳转有两种形式:
- 重定向:地址栏会发生变化,执行完整个程序成之后跳转
- 转发:地址栏不会发生变化,执行到转发的代码立刻无条件跳转

我们目前知道Servlet服务方法中,有一个response对象,肯定可以调用此对象的sendRedirect()函数进行跳转,这种跳转属于重定向操作,可以传递session域的信息,实际上在Servlet中进行重定向操作就是使用sendRedirect()。
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		String path = request.getContextPath();//取得项目的根路径
		if(username.equals("jjm") && password.equals("jjm123")) {
			//登录成功
			//将用户信息设置到session域中
			HttpSession session = request.getSession(true);
			session.setAttribute("accName", username);
			session.setAttribute("accBalance", 0);
			//跳转到books.jsp中
			response.sendRedirect(path+"/jsp/books.jsp"); //重定向
		}else {
			//跳转到登录失败页面
			response.sendRedirect(path+"/jsp/fail.jsp");//重定向
		}
	}

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

像登录操作来说,我们使用session域存储用户信息,然后进行重定向操作到其他界面,是比较常见的操作,
但是如果不是登录业务,比如说是图书信息的查询,那么只要在图书信息页面获得图书的数据,
而其他页面不需要图书的数据,不需要将图书的数据放到session域中,而是放在请求域中,
也就是我们之前讲的request范围,但是request范围进行重定向之后获取不到,只能使用转发,
那么转发又如何操作呢?在request对象中提供了一个方法:
RequestDispatcher getRequestDispatcher(String path)返回了一个RequestDispatcher 对象,
而此对象有个转发的方法:
void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException,

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		String path = request.getContextPath();
		if(username.equals("jjm") && password.equals("jjm123")) {
			//登录成功
			//将用户信息设置到session域中
			HttpSession session = request.getSession(true);
			session.setAttribute("accName", username);
			session.setAttribute("accBalance", 0);
			//跳转到books.jsp中
//			response.sendRedirect(path+"/jsp/books.jsp"); //重定向
			
			//查询图书信息,将图书信息加入到请求域中,进行转发到books.jsp
			List<String> books = new ArrayList<>();
			books.add("1001		Java		100");
			books.add("1002		Html		120");
			books.add("1003		C++			80");
			request.setAttribute("books", books);//将图书数据加入到请求域中
			
//			RequestDispatcher rep = request.getRequestDispatcher("/jsp/books.jsp");//获得转发对象
//			rep.forward(request, response);//执行转发
			request.getRequestDispatcher("/jsp/lbooks.jsp").forward(request, response);
			
		}else {
			//跳转到登录失败页面
			response.sendRedirect(path+"/jsp/fail.jsp");//重定向
		}
	}
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	
		request.setCharacterEncoding("utf-8");
		String userName = request.getParameter("userName");
		String passWord = request.getParameter("passWord");
		Connection conn = null;
		PreparedStatement pstate = null;
		ResultSet res = null;
		boolean flag = false;
		String realName = null;
		try {
			conn = DBConnection.getMySQLConnection();
			String sql = "select user_id,real_name from user_info where user_name = ? and pass_word = ?";
			pstate = conn.prepareStatement(sql);
			pstate.setString(1,userName);
			pstate.setString(2,passWord);
			res = pstate.executeQuery();
			while(res.next()){
				realName = res.getString(2);
				flag = true;
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				DBConnection.closeMySQL(conn, pstate, res);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		if(flag) {
		//	登录成功,将用户的真实名称设置到session域对象中,并且转发到success.jsp
			HttpSession session = request.getSession();
			session.setAttribute("realName", realName);
			
//获得转发的对象,且设置转发地址
//RequestDispatcher rdp = request.getRequestDispatcher("/servletLogin/success.jsp");
//	rdp.forward(request, response);//执行转发
request.getRequestDispatcher("/servletLogin/success.jsp").forward(request, response);
//执行转发
		}else {
		// 登录失败,重定向到fail.jsp
			String path = request.getContextPath();
			response.sendRedirect(path + "/servletLogin/fail.jsp");
		}
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}
}

2.7 Servlet生命周期

一般在面试过程中,对于JavaWeb来说,问的比较多的也就是Servlet,
如果是面试更高级的程序员,比如架构师才会问一些底层的问题。
Servlet生命周期有四个步骤:
- Servlet加载:1次
- Servlet初始化:1次
- 服务:多次
- 销毁:1次
Serlvet生命周期和人的生命周期非常相似,人的话被孕育生命1次,出生1次,成长和生活多次,死亡1次。

对于Servlet来说,生命周期对应方法:
- 加载:tomcat会自动进行,不需要我们去了解
- 初始化:
init(ServletConfig config),可以获得初始化参数的初始化操作
init(),直接初始化操作
- 服务:service(),doGet(),doPost()
- 销毁:destroy()
@WebServlet("/ServletDemo06")
public class ServletDemo06 extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	//携带参数的初始化
	public void init(ServletConfig config) throws ServletException {
		System.out.println("携带参数的初始化");
	}

	//不携带参数的初始化
	public void init() throws ServletException {
		System.out.println("不携带参数的初始化");
	}

	//销毁
	public void destroy() {
		System.out.println("销毁");
	}
	
	//service服务
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("service服务");
	}

	//doGet服务
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("doGet服务");
	}

	//doPost服务
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("doPost服务");
	}
}
通过以上代码运行,发现Servlet生命周期结论:
1.Servlet初始化是在Servle第一次服务之前执行,而且初始化只执行一次
2.在Tomcat关闭的时候进行销毁

问题1:初始化方法有带参数和不带参数的,什么时候会调用不带参数的呢?
- 在两个初始化方法都复写的情况下,调用带参的初始化方法。
- 只复写无参初始化方法,那么只会调用无参初始化方法。

服务可以执行多次。
问题2:服务的方法目前只调用service,什么时候调用doGet或者doPost呢?现在浏览器直接访问默认是一个get请求。
- 如果Servlet程序中复写了service服务方法之后,doGet和doPost服务方法不会执行,所有的服务都调用service服务方法。
- 如果Servlet程序中没有复写service方法,那么会调用doGet或者doPost方法进行服务。

- 在Servlet的底层,是如何区分调用doGet还是doPost的呢?
实际上service是一个最高的服务方法,当前的Servlet程序中没有复写service方法的时候,
会调用父类的service方法,而且是由父类的service方法区分Servlet程序中到底是调用doGet还是doPost方法

总结

1.Servlet是sun公司推出的最早的动态web的实现方式,Servlet和jsp没有本质的区别,都是动态web的实现方式,
都是后端的语言,Jsp实际上就是一个Servlet。不同之处在于Servlet使用纯Java语言,而Jsp是Html+Java;
2.Servlet要使用浏览器访问的话有两种配置方式:
一种是通过web.xml配置(不建议使用),另外一种就是通过注解的方式进行;
3.Servlet中取得其他常用的内置对象,除了pageContext之外,其他的都比较简单;
4.Servlet中可以进行重定向和转发,重定向使用的是response对象,
转发使用的是RequestDispatcher接口,此接口的对象可以通过request取得;
8.理解Servlet生命周期,就将Servlet生命周期比作是人的生命周期。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值