Servelet

1. 数据库和浏览器的交互

  1. servlet获取前端页面中的数据
  2. servlet 将数据传入dao层
  3. Dao层把数据存储到数据库
  4. 数据库将反馈结构传送给dao层
  5. Dao层将结果给servlet
  6. servlet把得到的结果展示再浏览器上

2. What is Servlet

  • Servlet是服务器端的小程序,是tomcat的核心组件,可以获取客户端的请求信息,也可以给客户端响应信息。
  • 狭义上的概念:javax.servlet.Servlet接口及其子接口都属于servlet
  • 广义上的概念:servlet接口的实现类都属于servlet

3. Servlet 原始部署步骤

1) 实现Servlet接口

package com.wy.Day11_Practice;

import javax.servlet.*;
import java.io.IOException;

/**
 * @author HelloWorld
 * @create 2021-05-24-20:07
 * @email 154803771@qq.com
 */
public class Hello implements Servlet {
    // 初始化方法
    @Override
    public void init(ServletConfig config) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    // 处理客户端请求
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {

    }

    @Override
    public String getServletInfo() {
        return null;
    }

    // 销毁servlet
    @Override
    public void destroy() {

    }
}

2) 在web.xml注册servlet

<?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名称,和servlet的类名保持一致-->
        <servlet-name> Hello</servlet-name>
<!--        设置servlet全类名-->
        <servlet-class>com.wy.Day11_Practice.Hello</servlet-class>
    </servlet>
    
<!--    设置映射地址-->
    <servlet-mapping>
<!--        通过该值映射servlet的名称-->
        <servlet-name>Hello</servlet-name>
<!--        浏览器中的url地址,要加 /-->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

3). 在index.jsp中添加 a 标签

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <title>JSP - Hello World</title>
</head>
<body>
<h1><%= "Hello World!" %>
</h1>
<br/>
<a href="hello-servlet"> hello </a>
</body>
</html>

4. Servlet生命周期

  • 构造器: 第一次请求servlet调用,创建Servlet实例
  • Init(): 初始化方法,第一次请求时被调用,在整个生命周期中只被调用一次
  • Service(): 每次被请求都会调用
  • Destory(): 销毁时调用

5. Servlet注解

@WebServlet(name = "LoginServlet", value = "/LoginServlet")		

or

@WebServlet(name = "LoginServlet", urlPatterns = "/LoginServlet")

​ <url - pattern> 配置方式

  1. 绝对路径 => / LoginServlet
  2. 目录匹配 => / * 匹配目录下的全部内容都可以访问
  3. 扩展后缀名匹配 => * .action

6. doGet() 和 doPost()

  • 请求方式为get 调用doGet()
  • 请求方式为post 调用doPost()

get 和 post的区别

  • GET在浏览器后退刷新时是无害的,而POST会再次提交请求。
  • GET产生的URL地址可以被收藏为书签,而POST不可以。
  • GET请求会被浏览器主动cache,而POST不会,除非手动设置。
  • GET请求只能进行url编码,而POST支持多种编码方式。
  • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
  • GET请求在URL中传送的参数是有长度限制的,而POST没有。
  • 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
  • get 的参数直接展示在URL上,post的数据只会被保存到浏览器历史或服务器日志上
  • GET参数通过URL传递,POST放在Request body中。

7. 请求与响应

  • HttpServletRequest 请求 => 从浏览器端接收到服务器端
  • HttpServlletResponse 响应 => 从服务器端发送到浏览器端

7.1 请求

7.1.1 获取请求行中的数据
  1. 获取当前的请求方式

    • String method = request.getMethod();
      
  2. 获取get请求方式中的用户提交数据

    • String queryString = request.getQueryString();
      
7.1.2 获取当前请求路径
  1. 获取请求全路径

    • StringBuffer requestURL = request.getRequestURL();
      
  2. 获取当前请求路径,不包含主机地址

    • String requestURI = request.getRequestURI();
      
  3. 获取当前项目名称

    • String contextPath = request.getContextPath();
      
7.1.3 获取请求头中的数据
  1. 获取当前请求头所在页面

    String referer = request.getHeader("Referer");
    
  2. 获取User-Agent

    String header = request.getHeader("User-Agent");
    
7.1.4 获取表单中的数据
  1. 获取单条信息

    String username = request.getParameter("username");
    String password = request.getParameter("password");
    String hobby = request.getParameter("home");
    
  2. 获取checkbox中的数据

    String[] hobbies = request.getParameterValues("hobby");
    
补充
  1. request.getAttribute(“name”)可得到JSP页面一表单中控件的Value。其实表单控件中的Object的 name与value是存放在一个哈希表中的,所以在这里给出Object的name会到哈希表中找出对应它的value。

  2. 而不同页面间传值使用request.setAttribute(key, value)时,只会从a.jsp到b.jsp一次传递,之后这个request就会失去它的作用范围,再传就要再设一个 request.setAttribute()。而使用session.setAttribute(key, value)会在一个过程中始终保有这个值。

7.2 响应

7.2.1 响应普通文本
PrintWriter writer = response.getWriter();
writer.print("寻寻觅觅,凄凄惨惨戚戚");
7.2.2 响应表格
// 解决乱码 charset=utf-8
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
// 响应表格
writer.append("<h1>表格<h1>");
writer.append("<table>");
writer.append("<tr>");
writer.append("<th>编号</th>");
writer.append("<th>姓名</th>");
writer.append("<th>性别</th>");
writer.append("<th>地址</th>");
writer.append("</tr>");

writer.append("<tr>");
writer.append("<td>1</th>");
writer.append("<td>wy</th>");
writer.append("<td>男</th>");
writer.append("<td>敖德萨</th>");
writer.append("</tr>");
writer.append("</table>");
7.2.3 响应图片(提供文件下载)
// 1.获取文件路径
String realPath = getServletContext().getRealPath("/static/image/Bg.jpg");
// 2.获取输入流对象
FileInputStream fileInputStream = new FileInputStream(realPath);
// 3.获取文件类型
String mimeType = getServletContext().getMimeType(realPath);
// 4.将文件类型返回给浏览器
response.setHeader("Content-Type", mimeType);
 // 文件名要和资源名保持一致
String fileName = "背景.jpg";
// 处理下载中的乱码问题
String header = request.getHeader("User-Agent").toLowerCase(Locale.ROOT);
// 火狐的乱码处理
if (header.contains("firefox")) {
 fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);

} else {
 fileName = URLEncoder.encode(fileName, "utf-8")  ;
}
// 5.让浏览器已下载的方式处理该文件

response.setHeader("Content-Disposition", "attachment; filename="+fileName);

// 6.实现下载
ServletOutputStream outputStream = response.getOutputStream();
byte[] datas = new byte[1024];
int len = 0;
while ((len = fileInputStream.read(datas)) != -1) {
 outputStream.write(datas, 0, len);
}
outputStream.close();
fileInputStream.close();

8. 转发和重定向

  • 转发 :客户端向服务器发送请求,服务器响应转发请求,直接给用户返回跳转界面,一次请求

    request.getRequestDispatcher("/LoginSuccessful.html").forward(request, response);
    
  • 重定向:客户端发送请求,服务器返回客户端302状态码,提供客户端新的访问地址,客户端请求新地址, 两次请求

    response.sendRedirect(request.getContextPath() + "/LoginSuccessful.html");
    // request.getContextPath() =>  /当前项目名称,而/又在浏览器中解析,所有会被解析为主机地址,最终就形成了完整的绝对地址
    

​ 区别

  • 转发往服务器发送一次请求,重定向往服务器发送两次请求
  • 转发是在服务器内部完成 ,客户感知不到;响应是给客户端302状态码,让客户端去访问新的地址
  • 使用转发地址栏不发生变化;使用重定向地址栏发生变化
  • 使用转发可以访问WEB-INF下的资源;使用重定向不可以访问WEB-INF下的资源。因为WEB-INF对客户端的请求做了一层隔离,所以说,浏览器直接请求WEB-INF 下的资源是不允许的。

9. 请求响应中的乱码问题

9.1 请求中的乱码

  1. 编码与解码

    • 浏览器编码: 浏览器中的编码格式由html中的meta的

      ====

      chart属性值指定,通常为 utf-8

    • 服务器解码:服务器的解码格式为 iso-8859-1

  2. post请求

    • post请求 在servlet中解码

    • request.setCharacterEncoding(“utf-8);
      
  3. get请求

    • get请求,由Tomcat解码

    • Tomcat8 默认解码格式为 utf - 8 不用配置解码格式

    • Tomcat7 默认解码格式为 iso8859-1 需要在 cof / server.xml 文件中加入 URIEncoding=“utf-8”;

      <Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" 			protocol="HTTP/1.1" redirectPort="8443"/>
      

9.2响应中的乱码

  1. 编码与解码

    • 服务器编码: 默认格式为 iso-8859-1
    • 客户端解码: 默认格式为GBK
  2. response.setContentType("text/html;charset=utf-8");	
    

10. web中的路径问题

  1. “/” 代表绝对路径
  2. 由浏览器解析 “/” 代表当前主机地址目录下
    • a标签中的href
    • scrip标签中的src
    • link标签中的href
    • form标签中的action
    • 重定向,request.getContextPath() 得到的地址 => / 当前项目名称,"/" 表示主机地址
  3. 由服务器解析 "/ " 代表当前项目名称目录下 包括 https://主机地址 端口号/ 项目名称
    • 转发
    • servletContext.realPath()
    • web.xml文件中的url-pattern标签
  4. base 标签
    • 浏览器的地址在发送请求时会在地址前加上base标签中的href的属性值

11. 反射机制处理多方法请求

  1. <form action="UserServlet03?way=doLogin" method="post">
    
    • 提交方式只能为post
  2. 将反射机制封装在Base工具类

    @WebServlet(name = "BaseServlet", value = "/BaseServlet")
    public class BaseServlet extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 1.设置编码为utf-8
            request.setCharacterEncoding("utf-8");
    
            // 2.获取请求中的way的属性值
            String way = request.getParameter("way");
    
            // 3.通过反射获取对应的方法
            Method method = null;
            try {
                method = this.getClass().getDeclaredMethod(way, HttpServletRequest.class, HttpServletResponse.class);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
    
            // 获取具有protected属性方法的访问权
            assert method != null;
            method.setAccessible(true);
                // 使用方法
            try {
                method.invoke(this, request, response);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
    
        }
    }
    
  3. UserServlet继承Base工具类

    @WebServlet(name = "UserServlet03", value = "/UserServlet03")
    public class UserServlet extends BaseServlet{
        protected void doLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            System.out.println(username);
            System.out.println(password);
    
            response.sendRedirect(request.getContextPath() + "/success.html");
        }
    
        protected void doRegister(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            request.setCharacterEncoding("utf-8");
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            String sex = request.getParameter("sex");
            String email = request.getParameter("email");
            System.out.println("");
            request.getRequestDispatcher("/success.html").forward(request, response);
        }
    

12. 杀掉某一端口对应的进程

  1. 查看计算机中所有进程 netstat -nao
  2. 找到某端口对应的进程的PID
  3. taskkill /pid 具体pid值 /f

优化版

查看被占用端口对应的 PID

输入命令:

netstat -aon|findstr “8081”

结束进程
强制(/F参数)杀死 pid 为 9088 的所有进程包括子进程(/T参数):

taskkill /T /F /PID 9088

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐