CT的JavaWeb学习(6)——Servlet

6 Servlet

6.1 Servlet技术

6.1.1 Servlet简介

  1. Servlet是JavaEE规范之一。接口
  2. Servlet是JavaWeb三大组件之一。三大组件:Servlet程序、Filter过滤器、Listener监听器
  3. Servlet是运行在服务器上的一个Java小程序,可以接收并响应2客户端的请求

6.1.2 手动创建Servlet

  1. Servlet接口的service方法
  2. 在web.xml中配置相应访问地址
  3. 根据http://localhost:8080/05_web/hello访问Servlet程序
 public class HelloServlet implements Servlet {   
	@Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Hello Servlet 被访问了");
    }
 }
<!--servlet标签给Tomcat配置Servlet程序-->
<servlet>
    <!--servlet-name给Servlet程序起一个别名-->
    <servlet-name>HelloServlet</servlet-name>
    <!--servlet-class是Servlet程序的全类名-->
    <servlet-class>com.ct.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet-mapping给Servlet程序配置访问地址-->
<servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <!--url-pattern配置访问地址-->
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HgRte2Gj-1645450757606)(C:\Users\Tao\AppData\Roaming\Typora\typora-user-images\image-20220120161058744.png)]

6.1.3 Servlet生命周期

  1. 执行Servlet构造器方法

  2. 执行init初始化方法

    以上两种方法只在第一次访问时创建Servlet程序使用

  3. 执行service方法:每次访问都会调用

  4. 执行destroy销毁方法:在web工程停止时执行

6.1.4 GET和POST请求的分发处理

Service方法本身无法对请求类型GET和POST分别处理,所以我们手动编写方法来处理请求

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    //获取请求的类型
    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
    String method = httpServletRequest.getMethod();
    //执行相应的操作
    if("GET".equals(method)){
        System.out.println("get请求");
    }else if("POST".equals(method)){
        System.out.println("post请求");
    }
}

优化后

@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    //获取请求的类型
    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
    String method = httpServletRequest.getMethod();
    if("GET".equals(method)){
        doGet();
    }else if("POST".equals(method)){
        doPost();
    }
}
public void doGet(){
    System.out.println("get请求");
}
public void doPost(){
    System.out.println("post请求");
}

6.1.5 通过继承HttpServlet实现Servlet程序

实际项目开发中,都是使用继承HttpServlet类的方式实现Servlet程序

  1. 编写一个类继承HttpServlet类
  2. 根据业务需要重写doGet和doPost方法
  3. 到web.xml中配置Servlet程序的访问地址
public class HelloServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("HelloServlet2的doGet方法");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("HelloServlet2的doPost方法");
    }
}
<servlet>
    <servlet-name>HelloServlet2</servlet-name>
    <servlet-class>com.ct.servlet.HelloServlet2</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>HelloServlet2</servlet-name>
    <url-pattern>/hello2</url-pattern>
</servlet-mapping>

6.1.6 使用IDEA帮助创建Servlet程序

右键包->new->Servlet

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0xY1v7Nl-1645450757608)(C:\Users\Tao\AppData\Roaming\Typora\typora-user-images\image-20220120170229673.png)]

6.1.7 Servlet程序的体系

interface Servlet:定义Servlet程序访问规范

  • class GenericServlet:实现了Servlet接口,做了很多空的实现。并有一个ServletConfig类的对象
    • abstract class HttpServlet:实现了service()方法,封装了请求的分发处理doGet()和doPost()
      • class 自定义子类:只需要重写doGet()和doPost()实现我们的需求

6.2 ServletConfig类

ServletConfig是Servlet程序的配置信息类

Servlet程序默认是在第一次访问时创建,ServletConfig是每个Servlet创建时,就创建一个对应的ServletConfig对象

6.2.1 ServletConfig三个作用

  1. 获取Servlet程序的别名servlet-name的值
  2. 获取初始化参数init-param
  3. 获取ServletContext对象

三大作用实现

@Override
public void init(ServletConfig servletConfig) throws ServletException {
    
    System.out.println("别名是"+servletConfig.getServletName());

    String username = servletConfig.getInitParameter("username");
    String url = servletConfig.getInitParameter("url");
    System.out.println("username:"+username+" url:"+url);

    ServletContext servletContext = servletConfig.getServletContext();
    System.out.println("servletContext对象:"+servletContext);
    
}

init-param如何配置,在web.xml中

<servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>com.ct.servlet.HelloServlet</servlet-class>
    <!--init-param是初始化参数-->
    <init-param>
        <param-name>username</param-name>
        <param-value>CT</param-value>
    </init-param>
    <init-param>
        <param-name>url</param-name>
        <param-value>jdbc:mysql://localhost:3306/test</param-value>
    </init-param>
</servlet>

tips:

  1. ServletConfig只能获取自己Servlet程序的init-param参数
  2. 重写init方法,一定要调用父类的init方法:super.init(config);

6.3 ServletContext类

  1. ServletContext是一个接口,它表示Servlet上下文对象
  2. 一个web工程,只有一个ServletContext对象实例
  3. ServletContext对象是一个域对象
  4. ServletContext在web工程部署启动时创建,在web工程停止时销毁

域对象:可以像Map一样存取数据的对象。域是指存取数据的操作范围,是整个web工程。域中的数据是全局的

删除
Mapput()get()remove()
域对象setAttribute()getAttribute()removeAttribute()

6.3.1 ServletContext类的四个作用

  1. 获取web.xml配置的上下文参数context-param
  2. 获取当前工程路径,格式:/工程路径
  3. 获取工程部署后在服务器硬盘上的绝对路径
  4. 像Map一样存取数据

6.4 HTTP协议

6.4.1 HTTP协议简介

6.4.2 请求

在这里插入图片描述在这里插入图片描述

常用请求头

Accept:表示客户端可以接收的数据类型

Accept-Language:表示客户端可以接收的语言类型

User-Agent:表示客户端浏览器的信息

Host:表示请求时的服务器ip和端口号

GET和POST请求举例

GET:

  1. form标签 method=get
  2. a标签
  3. link标签引入css
  4. Script标签引入js文件
  5. img标签引入图片
  6. iframe引入html页面
  7. 在浏览器地址栏输入地址后敲Enter

POST:

  1. form标签 method=post

6.4.3 响应

在这里插入图片描述

常见的响应码

200:请求成功

302:请求重定向

404:表示服务器收到请求,但是你要的数据不存在

500:表示服务器收到请求,但是服务器代码错误

MIME类型说明

MIME是HTTP协议中数据类型
在这里插入图片描述

6.5 HttpServletRequest类

每次有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议解析好封装到Request对象中,然后传递到service方法中给我们使用。我们可以通过HttpServletRequest对象,获取所有请求的信息

6.5.1 HttpServletRequest类的常用方法

  • getRequestURI():获取请求的资源路径
  • getRequestURL():获取请求的绝对路径
  • getRemoteHost():获取客户端ip
  • getHeader(String s):获取请求头的内容
  • getMethod():获取请求方式
public class RequestAPIServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("URI=>"+req.getRequestURI());
        System.out.println("URL=>"+req.getRequestURL());
        System.out.println("客户端 ip=>"+req.getRemoteHost());
        System.out.println("请求头User-Agent=>"+req.getHeader("User-Agent"));
        System.out.println("请求的方式"+req.getMethod());
    }
}

6.5.2 如何获取请求参数

提交页面form.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:8080/07_Servlet/parameterServlet" method="post">
        用户名:<input type="text" name="username" ><br/>
        密码:<input type="password" name="password"><br/>
        兴趣爱好:<input type="checkbox" name="hobby" value="cpp">C++
        <input type="checkbox" name="hobby" value="java">Java
        <input type="checkbox" name="hobby" value="js">JavaScript<br/>
        <input type="submit">
    </form>
</body>
</html>

在这里插入图片描述
如何获取请求参数

public class ParameterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("-----------doGet-------------");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobbies = req.getParameterValues("hobby");
        System.out.println(username);
        System.out.println(password);
        System.out.println(Arrays.asList(hobbies));
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求体的字符集为UTF-8,从而解决post中文乱码问题,要在获取参数之前调用才有效
        req.setCharacterEncoding("UTF-8");
        System.out.println("-----------doPost-------------");
    }
}

6.5.3 请求流程

  1. 用户发请求,action=add
  2. 项目中,web.xml找到url-pattern = /add
  3. 然后找到servlet-name
  4. 再通过servlet-name定位到servlet-class
  5. 根据用户发送的GET或POST请求,执行相应的doGet()或doPost()

* 一次问题

说明,数据库驱动正确,但是连接不上

//获取连接
protected Connection getConn(){
    try {
        Class.forName(DRIVER);
        return DriverManager.getConnection(URL,USER,PASSWORD);
    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    }
    return null;
}

解决方法

  1. maven配置

  2. 删除out文件夹里artifacts和production下的内容

    文件->项目结构->工件,删除再重新添加。

  3. 将mysql-connector的jar包放在Tomcat安装目录的lib目录下

6.6 HttpServletResponse类

HttpServletResponse类和HttpServletRequest类一样,每次请求Tomcat服务器都会创建一个Response对象传递给Servlet程序。

HttpServletRequest表示请求过来的信息,HttpServletResponse表示响应的信息

我们需要设置返回给客户端的信息,都可以使用HttpServletResponse对象来设置

6.6.1 两种响应流的介绍

HttpServletResponse可以通过以下方法获取字节流和字符流

字节流:getOutputStream()

字符流:getWriter()

两个方法不能同时使用

6.6.2 如何往客户端回传数据

public class ResponseIOServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置服务器的字符集
        resp.setCharacterEncoding("UTF-8");
        //通过响应头设置浏览器的字符集
        resp.setHeader("Content-Type","text/html;charset=UTF-8");
        //服务器回传数据
        PrintWriter writer = resp.getWriter();
        writer.write("如何评价");
    }
}

修改字符集方式二(推荐

//方式二:同时设置服务器和客户端的字符集
//但是要在获取流之前调用才有效
resp.setContentType("text/html;charset=UTF-8");

6.7 session会话追踪技术

Http是无状态的:服务器无法判断这两次请求是同一个客户端发过来的,还是不同客户端发的

通过会话跟踪技术来解决无状态问题

  • 客户端发请求时,服务器获取session
    • 第一次:服务器获取不到session,则会创建新的sessionID,然后响应给客户端
    • 之后的请求:客户端的请求会带上sessionID,服务器就能获取到session,从而判断并区分客户端
//演示session
public class Servlet03 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取session,如果没有创建一个新的
        HttpSession session = req.getSession();
        System.out.println("session ID: "+session.getId());
    }
}

6.7.1 常用API

  • Request.getSession()
    • 空参:获取当前会话,没有则创建一个新的会话
    • true:同空参
    • false:获取当前会话,没有则返回null,不会创建新的会话
  • session.getId():获取sessionID
  • session.isNew():判断会话是否是新创建的
  • session.getMaxInactiveInterval():会话非激活间隔时长,1800ms=半小时,可以set
  • session.invalidate():强制让会话失效

6.7.2 session保存作用域

session中带有作用域,持续时间与会话相同,作用域为当前会话。

同样是Attribute,数据以Key-Value保存。

  • session.setAttribute(k,v)
  • session.getAttribute(k)
  • session.removeAttribute(k)

6.8 请求转发

在这里插入图片描述
特点:

  1. 浏览器地址栏没有变化
  2. 他们是一次请求
  3. 他们共享Request域中的数据
  4. 可以转发到WEB-INF目录下
  5. 不允许访问工程以外的资源

Servlet1

public class Servlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求的资料
        String username = req.getParameter("username");
        System.out.println("在Servlet1查看参数:"+username);

        //
        req.setAttribute("key1","柜台1的章");

        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servlet2");

        requestDispatcher.forward(req,resp);
    }

}

Servlet2

public class Servlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求的资料
        String username = req.getParameter("username");
        System.out.println("在Servlet2查看参数:"+username);

        //查看柜台1是否有章
        Object key1 = req.getAttribute("key1");
        System.out.println("柜台1是否有章:"+key1);

        //处理自己的业务
        System.out.println("Servlet2处理自己的业务");
    }

}

6.9 请求重定向

服务器端在响应第一次请求的时候,让客户端再向另外一个URL发出请求,从而达到转发的目的。它本质上是两次HTTP请求,对应两个request对象。(因为之前的地址可能已经被废弃)
在这里插入图片描述

特点:

  1. 浏览器地址栏会发生变化
  2. 实质是两次请求
  3. 不会共享域数据
  4. 无法访问WEB-INF目录下的资源
  5. 可以访问工程外的资源

方式一

public class Response1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("曾到此一游 Response1");
        //设置状态码302,表示重定向
        resp.setStatus(302);
        //设置响应头,说明新的地址
        resp.setHeader("Location","http://localhost:8080/07_Servlet/response2");
    }
}

方式二(推荐)

public class Response1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect("http://localhost:8080/07_Servlet/response2");
    }
}

6.10 Thymeleaf

视图模板技术,类似jsp。

在html页面上加载java内存中的数据,称为渲染(render)。

6.10.1 使用流程

  1. 导入thymeleaf依赖
  2. 新建一个Servlet类ViewBaseServlet
  3. 在web.xml文件中配置
    • 配置前缀:view-prefix
    • 配置后缀:view-suffix
  4. 使Servlet类继承ViewBaseServlet
  5. 使用thymeleaf标签
</tr>
<tr  th:if="${#lists.isEmpty(session.fruitList)}">
    <td colspan="4">对不起,库存为空</td>
</tr>
<tr th:unless="${#lists.isEmpty(session.fruitList)}" th:each="fruit : ${session.fruitList}">
    <td th:text="${fruit.fname}"></td>
    <td th:text="${fruit.price}">5</td>
    <td th:text="${fruit.fcount}">20</td>
    <td><img src="images/delete.png" class="delete_images"/></td>
</tr>
/*thymeleaf会将逻辑视图名称对应到物理视图名称上去
* 逻辑:index
* 物理:prefix+"index"+suffix
* 举例: /      index  .html
* */

6.11 作用域

Servlet程序中域数据的存取范围分为:page、request、session、application

  • page:页面级别,几乎不用
  • request:一次请求范围有效->HttpServletRequest类
  • session:一次会话范围有效->HttpSession类
  • application:一次应用程序范围有效->ServletContext类

* 资源不生效问题

IDEA项目中的js,css文件不生效。

**解决方法:**build->Build Artifact->clean,然后再build->build Artifact->rebuild

* base标签

由于相对路径会参照当前浏览器地址栏中的地址来进行跳转,所以在普通使用a标签进行跳转时,会导致404返回错误的地址

使用base标签可以设置当前页面所有的相对路径工作时的参照路径,给所有相对路径提供一个基准

<!DOCTYPE html>
<html lang="zh_CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <base href="http://localhost:8080/07_Servlet/a/b/">
</head>
<body>
    这是a下的b下的c.html页面<br/>
    <a href="../../index.html">跳回首页</a>
</body>
</html>

* web中/的含义

/

  • 浏览器解析,得到:http://ip:port/
  • 服务器解析,得到:http://ip:port/工程路径
    • /servlet1
    • servletContext.getRealPath("/")
    • request.getRequestDispatcher("/")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值