自 MVC 规范出现后, Servlet 的责任开始明确下来, 仅仅作为控制器使用, 不再需要生成页面标签, 也不再做为视图层角色使用. servlet 通常被称为服务器端小程序, 是运行在服务器端的程序 . 用于处理用户的请求及响应.
一. Servlet 介绍
Servlet 是特殊的 Java 类, 这个 Java 类必须继承 HTTPServlet, 每个 servlet 可以响应用户的请求. Servlet 提供不同的方法用于相应用户的请求
doGet(): 用于相应客户端的 get 请求
doPost(): 用于响应客户端的 Post 请求
doPut(): 用于相应客户端的 put 请求
doDelete(): 用于相应客户端的 delete 请求
事实上, 客户端请求通常只有 get 和 post 两种, servlet 为了响应这两种请求, 必须重写 doPost()和 doGet()两个方法.
大部分时候, servlet 对于所有请求的响应都是都是完全一样的. 因此可以采用重写一个方法来代替上面四个方法: 只需要重写 service 方法即可响应客户端所有请求.
另外, HTTPServlet 还包括另外两个方法
init(ServletConfig config): 创建 servlet 实例时, 使用该方法初始化 Servlet 资源.
destroy(): 销毁 Servlet 实例时, 自动调用该方法回收资源
通常无需重写这两个方法. 除非需要初始化 Servlet 时, 完成某些资源初始化的方法, 才考虑重写 init()方法. 如果需要在销毁 Servlet 之前, 先完成某些资源的回收, 比如关闭数据库连接等, 才需要重写 destroy 方法.
Servlet 与 JSP 的区别在于:
Servlet 没有内置对象, 原 JSP 中的内置对象必须由程序显示创建
对于静态的 html 标签, servlet 必须使用页面输出流逐行输出
二. Servlet 配置
编辑好的 servlet 源文件并不能响应用户请求, 还必须将其编译成 class 文件 . 将编译后的 class 文件放在 web-INF/classes 路径下, 如果 servlet 有包, 则还应该将 class 文件放在对应的包路径下.
为了让 Servlet 响应用户请求, 还必须将 Servlet 配置在 web 应用中. 配置 Servlet 时, 需要修改 web.xml 文件
从 servlet3.0 开始, 配置 servlet 的两种方式
在 servlet 类中使用 @webServlet 注解进行配置
通过在 web.xml 文件中进行配置
使用注解 @webServlet 配置 Servlet 时, 常用的属性有
属性 | 是否必须 | 说明 |
asynsSupported | 否 | 指定该 Servlet 是否支持异步操作模式 |
displayName | 否 | 指定该 Servlet 的显示名 |
initParam | 否 | 用于为该 Servlet 配置参数 |
loadOnStartup | 否 | 用于将该 servlet 配置成 load-on-startup 的 Servlet |
name | 否 | 指定该 servlet 的名字 |
urlPatterns/value | 否 | 都指定 servlet 处理的 URL |
如果打算使用注解来配置 Servlet, 有两点需要指出:
不要在 web.xml 文件的根元素 (<web-app.../>) 中指定 metadata-complete="true".
不要在 web.xml 文件中配置该 servlet.
如果打算使用 web.xml 文件来配置该 Servlet, 则需要配置如下两个部分.
配置 Servlet 的名字: 对应 web.xml 文件中的 < servlet/>元素
配置 servlet 的 URL, 对应 web.xml 文件中的 < servlet-mapping/>元素. 这一步是可选的. 但如果没有为 Servlet 配置 URL, 则该 servlet 不能响应该用户请求.
三. JSP/Servlet 的生命周期
当 Servlet 在容器中运行时, 其实例的创建及销毁等都不是程序员决定的, 而是由 web 容器进行控制的的
创建 servlet 实例有两个时机
客户端第一次请求某个 Servlet 时, 系统创建该 Servlet 的实例: 大部分的 Servlet 都是这种 Servlet
Web 应用启动时立即创建 Servlet 实例, 即 load-on-startup Servlet.
每个 Servlet 运行都遵循如下生命周期
创建 Servlet 实例
Web 容器调用 Servlet 的 init 方法, 对 Servlet 进行初始化.
Servlet 初始化后, 将一直保存在容器中, 用于响应客户端的请求, 调用 doGet()或者 doPost()方法处理并响应请求, 或者统一使用 service 方法
web 容器决定销毁 Servlet 时, 先调用 Servlet 的 destroy()方法, 通常在关闭 Web 应用时销毁 Servlet.
四. load-on-startup Servlet
应用启动时就创建的 Servlet 通常是用于某些后台服务的 Servlet, 或者拦截很多请求的 Servlet, 这种 Servlet 通常作为应用的基础 Servlet 使用, 提供重要的后台服务.
配置 load-on-startup 的 Servlet 有两种方式
在 web.xml 文件中通过 < servlet.../>的子元素 < load-on-startup.../>进行配置
通过 @webServlet 注解的 loadOnStartup 属性指定
<load-on-startup.../>元素和 loadOnStartup 属性都只接受一个整型值, 这个整型值越小, Servlet 越优先实例化
五. 访问 servlet 的配置参数
配置 Servlet 时, 还可以增加额外的配置参数. 通过使用配置参数, 可以实现提供更好的可移植性, 避免将参数以硬代码的方式写在代码程序中.
设置参数的两种方式
通常 @webServlet 的 initParam 属性来指定
通过在 web.xml 文件的 < servlet.../>元素中添加 < init-param.../>指定
访问 Servlet 参数通过 servletConfig 对象完成, ServletConfig 提供如下方法.
String getInitParamter(String name): 用于获取初始化参数
六. 使用 Servlet 作为控制器
在标准的 Java EE 的 MVC 设计模式中 Servlet 仅作为控制器使用. JSP 作为表现层技术, 其作用有两点
负责收集用户请求参数
将应用的处理结果, 状态数据呈现给用户
servlet 仅充当控制器角色, 它的作用类似于调度员; 所有用户请求都发给 Servlet,Servlet 调用 Model 来处理用户请求, 并调用 JSP 来呈现处理结果; 或者 Servlet 直接调用 JSP 将应用的状态数据呈现给用户
model 通常由 JavaBean 充当, 所有业务逻辑, 数据访问逻辑都在 model 中实现. 事实上, 隐藏在 Model 下的可能还有很多丰富的组件, 例如 dao 组件, 领域对象等, 下面介绍了一个使用 Servlet 作为控制器的 MVC 应用, 该应用演示了一个简单的登录验证.
- <%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="" %>
- <html>
- <head>
- <title>new document</title>
- </head>
- <body>
- <span style="color:red;font-weight: bold;">
- <%
- if(request.getAttribute("err") != null){
- out.println(request.getAttribute("err")+"<br/>");
- }
- %>
- </span>
请输入用户名和密码:<br/>
- <form id="login" method="post" action="login">
- 用户名: <input type="text" name="username"><br/>
- 密 & nbsp; 码:<input type="password" name="pass"/><br/>
- <input type="submit" value="登录">
- </form>
- </body>
- </html>
- package java.gdut.servlet;
- import javax.servlet.RequestDispatcher;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpSession;
- import java.io.IOException;
- import java.sql.ResultSet;
- @WebServlet(name = "login",urlPatterns = "/login")
- public class LoginServlet extends javax.servlet.http.HttpServlet {
protected void service(javax.servlet.http.HttpServletRequest request,
- javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
- String errMsg = "";
- RequestDispatcher rd;
- String username = request.getParameter("username");
- String pass = request.getParameter("pass");
- try{
- DbDao db = new DbDao("jdbc:mysql://localhost:3306/tb_test","com.mysql.jdbc.Driver","sherman","a123");
- ResultSet rs = db.querry("select pass from user_inf where name=?",username);
- if(rs.next()){
- if(rs.getString("pass").equals(pass)){
- HttpSession session = request.getSession(true);
- session.setAttribute("name",username);
- rd=request.getRequestDispatcher("/welcome.jsp");
- rd.forward(request,response);
- }else{
- errMsg+="您的用户密码不符合, 请重新输入";
- }
- }else{
- errMsg+="您的用户名不存在, 请先注册";
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- if(errMsg != null && !errMsg.equals("")){
- rd = request.getRequestDispatcher("/login.jsp");
- request.setAttribute("err",errMsg);
- rd.forward(request,response);
- }
- }
- }
- package java.gdut.servlet;
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- public class DbDao {
- private Connection conn;
- private String url;
- private String driver;
- private String user;
- private String pass;
- public DbDao(String url, String driver, String user, String pass) {
- this.url = url;
- this.driver = driver;
- this.user = user;
- this.pass = pass;
- }
- public String getUrl() {
- return url;
- }
- public void setUrl(String url) {
- this.url = url;
- }
- public String getDriver() {
- return driver;
- }
- public void setDriver(String driver) {
- this.driver = driver;
- }
- public String getUser() {
- return user;
- }
- public void setUser(String user) {
- this.user = user;
- }
- public String getPass() {
- return pass;
- }
- public void setPass(String pass) {
- this.pass = pass;
- }
- /**
- * 获取数据库连接
- */
- public Connection getConn() throws Exception {
- if (conn == null) {
- Class.forName(this.driver);
- conn = DriverManager.getConnection(this.url, this.user, this.pass);
- System.out.println(conn);
- }
- return conn;
- }
- /**
- * 执行插入
- * @param sql
- * @param args
- * @return
- * @throws Exception
- */
- public boolean insert(String sql,Object... args) throws Exception{
- PreparedStatement prst = getConn().prepareStatement(sql);
- for (int i = 0; i <args.length ; i++) {
- prst.setObject(i+1,args[i]);
- }
- if(prst.executeUpdate() != 1){
- return false;
- }
- return true;
- }
- /**
- * 执行查询
- * @param sql
- * @param args
- * @return
- * @throws Exception
- */
- public ResultSet querry(String sql,Object... args)throws Exception{
- PreparedStatement prst = getConn().prepareStatement(sql);
- for (int i = 0; i < args.length; i++) {
- prst.setObject(i+1,args[1]);
- }
- return prst.executeQuery();
- }
- public void modify(String sql,Object... args)throws Exception{
- PreparedStatement prst = getConn().prepareStatement(sql);
- for (int i = 0; i < args.length; i++) {
- prst.setObject(i+1,args[1]);
- }
- prst.executeUpdate();
- prst.close();
- }
- public void closeConn()throws Exception{
- if(null != conn && !conn.isClosed()){
- conn.close();
- }
- }
- }
来源: http://www.bubuko.com/infodetail-2600389.html