Servlet

1. Tomcat

Tomcat是一个web应用服务器(或容器)。官网:here.
在这里插入图片描述

2. Servlet入门

  1. 创建html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="add" method="post">
    名称:<input type="text" name="fname"/><br/>
    价格:<input type="text" name="price"/><br/>
    库存:<input type="text" name="fcount"/><br/>
    备注:<input type="text" name="remark"/><br/>
    <input type="submit" value="添加"/>
</form>

</body>
</html>
  1. 创建Servlet类
    需要导入tomcat的库,其中包含javax扩展包serlet-api.jar
package com.atguigu.servlets;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AddServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	//post方式下,设置编码,防止中文乱码
    	需要注意的是,设置编码这一句代码必须在所有获取参数动作之前
    	//get方式目前不需要设置编码(基于tomcat8)
        req.setCharacterEncoding("utf-8");
        String fname = req.getParameter("fname");
        int price = Integer.parseInt(req.getParameter("price"));
        int fcount = Integer.parseInt(req.getParameter("fcount"));
        String remark = req.getParameter("remark");
        
        FruitDAO fruitDAO = new FruitDAOImpl();
        boolean flag = fruitDAO.addFruit(new Fruit(0, fname, price, fcount, remark));
        System.out.println(flag?"添加成功": "添加失败");
    }
}

  1. 在web.xml创建映射
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>AddServlet</servlet-name>
        <servlet-class>com.atguigu.servlets.AddServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>AddServlet</servlet-name>
        <url-pattern>/add</url-pattern>
    </servlet-mapping>
    <!--
    1. 用户发请求,action=add
    2. 项目中,web.xml中找到url-pattern = /add ->第12行
    3. 找第11行的servlet-name = AddServlet
    4. 找和servlet-mapping中servlet-name一致的servlet, ->第7行
    5. 找第8行的servlet-class ->com.atguigu.servlets.AddServlet
    6. 用户发送的是post请求(method),因此tomcat会执行AddServlet中的doPost方法
    -->
</web-app>

3. Servlet的继承关系

1.继承关系

javax.servlet.Servlet接口
	javax.servlet.GenericServlet抽象类
			javax.serlvet.http.HttpServlet 抽象子类       

2. 相关方法

javax.servlet.Servlet接口:
void init(config)-初始化方法
void service(request.response)-服务方法
void destroy() -销毁方法
javax.servlet.GenericServlet抽象类:
void service(request,response)-仍然是抽象的
javax.servlet.http.HttpServlet 抽象子类:
void service(request,response)-不是抽象的
1. String method = req.getMethod();获取请求的方式
2. 各种if判断,根据请求方式的不同,决定去调用不同的do方法

if (method.equals("GET")) {
                this.doGet(req, resp);
        } else if (method.equals("HEAD")) {
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } 
		......
3. 在HttpServlet这个抽象类中,do方法都差不多
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = lStrings.getString("http.method_get_not_supported");
        this.sendMethodNotAllowed(req, resp, msg);
    }
    
private void sendMethodNotAllowed(HttpServletRequest req, HttpServletResponse resp, String msg) throws IOException {
        String protocol = req.getProtocol();
        if (protocol.length() != 0 && !protocol.endsWith("0.9") && !protocol.endsWith("1.0")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }

3. 小结

  1. 继承关系: HttpServlet -> GenericServlet -> Servlet
    2) Servlet中的核心方法: init() , service() , destroy()
    3) 服务方法: 当有请求过来时,service方法会自动响应(其实是tomcat容器调用的)
    在HttpServlet中我们会去分析请求的方式:到底是get、post、head还是delete等等
    然后再决定调用的是哪个do开头的方法
    那么在HttpServlet中这些do方法默认都是405的实现风格-要我们子类去实现对应的方法,否则默认会报405错误
    4) 因此,我们在新建Servlet时,我们才会去考虑请求方法,从而决定重写哪个do方法

4. Servlet的生命周期

1) 生命周期:从出生到死亡的过程就是生命周期。对应Servlet中的三个方法:init(),service(),destroy()。
2) 默认情况下:
第一次接收请求时,这个Servlet会进行实例化(调用构造方法)、初始化(调用init())、然后服务(调用service())
从第二次请求开始,每一次都是服务
当容器关闭时,其中的所有的servlet实例会被销毁,调用销毁方法

//Servlet生命周期
public class Demo02Servlet extends HttpServlet {

    public Demo02Servlet() {
        System.out.println("正在实例化...");
    }
    
    @Override
    public void init() throws ServletException {
        System.out.println("正在初始化...");
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("正在服务...");
    }

    @Override
    public void destroy() {
        System.out.println("正在销毁...");
    }
}
正在实例化...
正在初始化...
正在服务...
正在服务...
正在销毁...

3) 通过案例我们发现:
- Servlet实例tomcat只会创建一个,所有的请求都是这个实例去响应。
- 默认情况下,第一次请求时,tomcat才会去实例化,初始化,然后再服务.这样的好处是什么? 提高系统的启动速度 。 这样的缺点是什么? 第一次请求时,耗时较长。
- 因此得出结论: 如果需要提高系统的启动速度,当前默认情况就是这样。如果需要提高响应速度,我们应该设置Servlet的初始化时机。
4) Servlet的初始化时机:
- 默认是第一次接收请求时,实例化,初始化
- 我们可以通过来设置servlet启动的先后顺序,数字越小,启动越靠前,最小值0。设置这个参数就可以在容器启动的时候来初始化该Servlet。

    <servlet>
        <servlet-name>Demo02Servlet</servlet-name>
        <servlet-class>com.atguigu.servlets.Demo02Servlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

5) Servlet在容器中是:单例的、线程不安全的
- 单例:所有的请求都是同一个实例去响应
- 线程不安全:一个线程需要根据这个实例中的某个成员变量值去做逻辑判断。但是在中间某个时机,另一个线程改变了这个成员变量的值,从而导致第一个线程的执行路径发生了变化
- 我们已经知道了servlet是线程不安全的,给我们的启发是: 尽量的不要在servlet中定义成员变量。如果不得不定义成员变量,那么不要去:①不要去修改成员变量的值 ②不要去根据成员变量的值做一些逻辑判断
在这里插入图片描述

5. 服务器内部转发以及客户端重定向

1) **服务器内部转发 **: request.getRequestDispatcher("...").forward(request,response);
- 一次请求响应的过程,对于客户端而言,内部经过了多少次转发,客户端是不知道的
- 地址栏没有变化
2) 客户端重定向response.sendRedirect("....");
- 两次请求响应的过程。客户端肯定知道请求URL有变化
- 地址栏有变化

服务器内部转发举例:
服务器内部转发
客户端重定向举例:
客户端重定向

6. 保存作用域

原始情况下,保存作用域有四个:
page(页面级别,现在几乎不用)
request(一次请求响应范围)
session(一次会话范围)
application(整个应用程序范围)

request(一次请求响应范围)

在这里插入图片描述

@WebServlet("/demo01")
public class Demo01Servlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setAttribute("uname", "lili");
        resp.sendRedirect("demo02");//不能取到
//        req.getRequestDispatcher("demo02").forward(req,resp);//可以取到
    }
}


@WebServlet("/demo02")
public class Demo02Servlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object uname = req.getAttribute("uname");
        System.out.println(uname);
    }
}

session(一次会话范围)

在这里插入图片描述
注意:左边两个框代表2个不同客户端。

@WebServlet("/demo01")
public class Demo01Servlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getSession().setAttribute("uname","lili");
        resp.sendRedirect("demo02");//可以取到
//        req.getRequestDispatcher("demo02").forward(req,resp);//可以取到
    }
}

@WebServlet("/demo02")
public class Demo02Servlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object uname = req.getSession().getAttribute("uname");
        System.out.println(uname);
    }
}

application(整个应用程序范围)

在这里插入图片描述

@WebServlet("/demo01")
public class Demo01Servlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext application = req.getServletContext();
        application.setAttribute("uname", "lili");
        resp.sendRedirect("demo02");//不同客户端都可以取到
//        req.getRequestDispatcher("demo02").forward(req,resp);//不同客户但都可以取到
    }
}

@WebServlet("/demo02")
public class Demo02Servlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object uname = req.getServletContext().getAttribute("uname");
        System.out.println(uname);
    }
}

7. 路径问题

1)相对路径

2)绝对路径
在这里插入图片描述

8. 再次学习Servlet的初始化方法

  1. Servlet生命周期:实例化、初始化、服务、销毁
  2. Servlet中的初始化方法有两个:init() , init(config)
    其中带参数的方法代码如下:
public void init(ServletConfig config) throws ServletException {
  this.config = config ;
  init();
}

另外一个无参的init方法如下:

public void init() throws ServletException{
}

如果我们想要在Servlet初始化时做一些准备工作,那么我们可以重写init方法
我们可以通过如下步骤去获取初始化设置的数据

  • 获取config对象:ServletConfig config = getServletConfig();
  • 获取初始化参数值: config.getInitParameter(key);
  1. 在web.xml文件中配置Servlet
 <servlet>
        <servlet-name>Demo01Servlet</servlet-name>
        <servlet-class>com.atguigu.servlet.Demo01Servlet</servlet-class>
        <init-param>
            <param-name>hello</param-name>
            <param-value>world</param-value>
        </init-param>
        <init-param>
            <param-name>uname</param-name>
            <param-value>jim</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>Demo01Servlet</servlet-name>
        <url-pattern>/demo01</url-pattern>
    </servlet-mapping>
  1. 也可以通过注解的方式进行配置:
@WebServlet(urlPatterns = {"/demo01"} ,
    initParams = {
        @WebInitParam(name="hello",value="world"),
        @WebInitParam(name="uname",value="jim")
    })

9. 学习Servlet中的ServletContext和

<context-param>
        <param-name>a</param-name>
        <param-value>b</param-value>
    </context-param>
  1. 获取ServletContext,有很多方法
    在初始化方法中: ServletContext servletContext = getServletContext();
    在服务方法中也可以通过request对象获取,也可以通过session获取:
    request.getServletContext();
    session.getServletContext();
  2. 获取初始化值:
    servletContext.getInitParameter(key);

10. 什么是业务层

1) Model1和Model2

MVC : Model(模型)、View(视图)、Controller(控制器)

  • 视图层:用于做数据展示以及和用户交互的一个界面
  • 控制层:能够接受客户端的请求,具体的业务功能还是需要借助于模型组件来完成
  • 模型层:模型分为很多种:有比较简单的pojo/vo(value object),有业务模型组件,有数据访问层组件,分为
    1. pojo/vo : 值对象, 简单的 Java 对象(Plain Old Java Object),实体类。
    2. DAO : 数据访问对象。Data Access Object
    3. BO : 业务对象。Business Object

2) 区分业务对象和数据访问对象:

1) DAO中的方法都是单精度方法或者称之为细粒度方法。什么叫单精度?一个方法只考虑一个操作,比如添加,那就是insert操作、查询那就是select操作…
2) BO中的方法属于业务方法,也实际的业务是比较复杂的,因此业务方法的粒度是比较粗的。

例如: 注册这个功能属于业务功能,也就是说注册这个方法属于业务方法。
那么这个业务方法中包含了多个DAO方法。也就是说注册这个业务功能需要通过多个DAO方法的组合调用,从而完成注册功能的开发。
注册:
1. 检查用户名是否已经被注册 - DAO中的select操作
2. 向用户表新增一条新用户记录 - DAO中的insert操作
3. 向用户积分表新增一条记录(新用户默认初始化积分100分) - DAO中的insert操作
4. 向系统消息表新增一条记录(某某某新用户注册了,需要根据通讯录信息向他的联系人推送消息) - DAO中的insert操作
5. 向系统日志表新增一条记录(某用户在某IP在某年某月某日某时某分某秒某毫秒注册) - DAO中的insert操作
6. …
3) 在库存系统中添加业务层组件
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值