Servlet详解

        欢迎来到 盛码笔记,这篇是我在 CSDN 的第一篇博文,标志着这段记录与分享的技术旅程的开始。欢迎留言交流,技术路上共同前行!

(一)web项目配置

web项目结构

创建一个web项目

  1. 创建一个普通的maven项目

  2. 在该项目的pom.xml文件中,修改打包方式(记得刷新一下)

    <packaging>war</packaging>
  3. 选择”文件——项目结构——Facet“,点”+“添加WebApp文件,和web.xml文件

  4. 最后调整文件位置,WEB-INF文件放到WebApp文件下

  5. 配置Tomcat插件,在项目文件pom.xml里添加插件坐标

  6. 最后装一个插件——Maven Helper就可以跑项目了(这里也可以本地部署Tomcat运行)

         <build>
             <plugins>
                 <plugin>
                     <groupId>org.apache.tomcat.maven</groupId>
                     <artifactId>tomcat7-maven-plugin</artifactId>
                     <version>2.2</version>
                 </plugin>
             </plugins>
         </build>

(二)Servlet快速入门

servlet是java提共的一门动态资源开发技术,实际上就是接口,我们需要定义Servlet类实现Servlet接口,并有Tomcat运行Servlet

  1. 创建web项目,导入Servlet依赖坐标

    注意:Servlet需要限制其作用域,即<scope>provided</scope>,provided指定Servlet在编译和测试阶段可用

    • 冲突:应用服务器已经提供了 Servlet API,打包的依赖可能会与服务器提供的版本冲突。

    • 冗余:Servlet API 会被重复包含,增加包的大小。

         <dependencies>
             <dependency>
                 <groupId>javax.servlet</groupId>
                 <artifactId>javax.servlet-api</artifactId>
                 <version>3.1.0</version>
             <!--  作用域(范围)-->
                 <scope>provided</scope>
             </dependency>
         </dependencies>
  2. 定义一个类实现Servlet接口,并重写所有方法

       @Override
         public void init(ServletConfig servletConfig) throws ServletException {
     ​
         }
     ​
         @Override
         public ServletConfig getServletConfig() {
             return null;
         }
     ​
         @Override
         public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
             System.out.println("hello world~");
         }
     ​
         @Override
         public String getServletInfo() {
             return "";
         }
     ​
         @Override
         public void destroy() {
     ​
         }
  3. 配置:在该类上使用@WebServlet,配置该Servlet的访问路径

     @WebServlet("/demo1")
     public class ServletDemo1 implements Servlet {}
  4. 访问:启动Tomcat,输入url访问该Servlet

     http://localhost:8080/tomcat/demo1

(三)Servlet执行流程

我们创建的实现Servlet接口的类由web服务器创建对象,并调用其中的方法

(四)Servlet生命周期

生命周期指一个对象从创建到被销毁的整个过程

Servlet运行在Servlet容器(web服务器)中,其生命周期由容器管理,分为四个阶段

  1. 加载和实例化:默认情况下,在Servlet被第一次访问时,容器就会创建Servlet对象。

    • 通过给loadOnStartup赋值可以改变对象创建时机,默认为负整数数

       @WebServlet(urlPatterns = "/demo1",loadOnStartup = 1)

      负整数:当Servlet第一次被访问时创建对象

      0或正整数:在启动服务器时创建Servlet对象,数字越小,优先级越高

  2. 初始化:在初始化之后,容器会调用Servlet的init()方法初始化该对象,完成一些加载文件配置等工作。该方法只调用一次

  3. 请求处理:当每次请求Servlet时,容器会调用service()方法处理。

  4. 服务终止:当需要释放资源或容器关闭时,容器会调用destory()方法完成资源释放。最后该对象会被垃圾回收器回收。

注意:当urlPattern错误时会报错A child container failed during start


(五)Servlet体系结构

 @WebServlet("/demo3")
 public class ServletDemo3 extends HttpServlet {
 ​
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         System.out.println("get...");
     }
 ​
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         System.out.println("post...");
     }
 }

HttpServlet根据请求类型进行判断,然后进行分别处理,以下代码实现类似效果

 public class MyHttpServlet implements Servlet {
     @Override
     public void init(ServletConfig servletConfig) throws ServletException {
 ​
     }
 ​
     @Override
     public ServletConfig getServletConfig() {
         return null;
     }
 ​
     @Override
     public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
 ​
         //1.根据请求方式判断处理
         HttpServletRequest request=(HttpServletRequest) servletRequest;
 ​
         String method = request.getMethod();
 ​
         //2.判断是get还是post
         if("GET".equals(method)){
             doGet(servletRequest,servletResponse);
         }else if(method.equals("POST")){
             doPost(servletRequest,servletResponse);
         }
     }
 ​
     protected void doGet(ServletRequest servletRequest, ServletResponse servletResponse) {
         System.out.println("get...");
     }
     protected void doPost(ServletRequest servletRequest, ServletResponse servletResponse) {
         System.out.println("post...");
     }
 ​
     @Override
     public String getServletInfo() {
         return "";
     }
 ​
     @Override
     public void destroy() {
 ​
     }
 }

(六)Servlet 的urlPattern配置


(七)Request对象

Request继承体系

Request获取请求数据

1.请求行POST /users/12345/orders?status=completed&limit=10 HTTP/1.1

方法作用例子
String getMethod()获取请求方式POST
String getContextPath()获取虚拟目录(项目访问路径)/users/12345/orders
StringBuffer getRequestURL()获取url(统一资源定位符)http://localhost:8080/tomcat/demo2
String getRequestURI()获取URI(统一资源标识符)/tomcat/demo2
String getQueryString()获取请求参数(GET请求方式)status=completed&limit=10
  1. 请求头

方法作用
String getHeader(String name)根据请求头名称,获取值
  1. 请求体

方法作用
ServletInputStream getInputString()获取字节输入流(图片,视频,音频等)
BufferReader getReader()获取字符输入流(纯字符)

因为GET和POST获取请求参数的方式不同,无法进行统一编程,所以采用通用方式获取请求参数

  • Request会根据方式进行判断,分别获取请求参数,再将参数切割后放入一个Map集合存储

方法作用
Map<String,String[]> getParameterMap()获取所有参数的Map集合
String[] getParameterValues(String name)根据名称获取参数值(数组)
String getParameter(String name)根据名称获取参数值(单个值)


Request获取请求数据乱码解决

  1. GET请求乱码

    GET请求的参数是通过URL传递的,而URL默认使用ISO-8859-1编码(一种单字节编码)。如果参数中包含非ASCII字符(如中文),而服务器端没有正确解码,就会导致乱码。

解决方法:手动解码

 String param = new String(request.getParameter("key").getBytes("ISO-8859-1"), "UTF-8");
 String param = new String(request.getParameter("username").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
  1. POST请求乱码

    POST请求的参数是通过请求体传递的,默认情况下,服务器可能没有正确设置请求体的编码方式。如果客户端发送的是UTF-8编码的数据,而服务器端使用ISO-8859-1或其他编码解析,就会导致乱码。

  • 解决方法:设置字符输入流编码

 request.setCharacterEncoding("UTF-8");


请求转发(forward)

一种服务器内部资源跳转的方式

实现方式

 request.getRequestDispatcher("/req5").forward(request,response);

当请求转发间需要共享数据时,使用Request对象

方法作用
void setAttribute(String name, Object o):存储数据到Requst域中
Object getAttribute(String key):根据key获取值
void removeAttribute(String key):根据key删除键值对

特点:

  1. 浏览器地址栏路径不会改变

  2. 只能转发到当前服务器内部资源

  3. 一次转发,可以共享Request内部资源

  4. 在一次请求中,请求转发只能执行一次。

注意:与前端页面连接

  • <input>输入框name属性要与键值对中的键值一致

  • 在浏览器中可以查看请求参数

  • 表单要设置method,即请求方式,默认为GET

  • 路径要用虚拟目录路径


(八)Response对象

Response设置响应数据功能

  1. 响应行HTTP/1.1 200 OK

    方法作用示例
    void setStatus(int sc):设置响应状态码200 OK
  2. 响应头:

     Content-Type: text/html; charset=UTF-8
     Content-Length: 1234
     Date: Mon, 23 Oct 2023 12:34:56 GMT

方法作用示例
void setHeader(String key, String value):设置响应头键值对Content-Length: 1234
  1. 响应体

    方法作用
    PrintWriter getWriter()获取字符输出流
    ServletOutputStream getOutputStream()获取字节输出流


Response重定向

一种资源跳转方式

 //重定向
 response.setStatus(302);
 response.setHeader("Location","/tomcat/resp2");
 ​
  //简化写法
 response.sendRedirect("/tomcat/resp2");//项目路径

特点:

  1. 浏览器地址栏路径发生改变

  2. 可以重定向到任意位置资源(服务器内部、外部均可)

  3. 两次请求不共享数据域


路径问题

是否需要添加虚拟目录(项目路径)?

  • 根据适用对象来进行判断

  • 如果是浏览器使用,需要加虚拟目录

  • 如果是服务器使用,不需要加虚拟目录

 <a ref="/request-demo/demo1">  加虚拟目录

注意:动态获取虚拟目录

         String contextPath = request.getContextPath();
 ​
         //简化写法
         response.sendRedirect(contextPath+"/resp2");


Response响应字符数据

         //获取字符输出流
         PrintWriter writer = response.getWriter();
         response.setHeader("content-type","text/html");
         writer.write("<h1>aaa<h1>");

解决中文乱码问题

原因:通过Response获取的字符输出流默认使用字符编码IOS-8859-1

 response.setContentType("text/html;charset=utf-8");

注意:字符输出流不需要手动关闭,Response对象销毁时,会自动关闭


Response响应字节数据

 //1.获取IO流
 FileInputStream fis = new FileInputStream("E:\\a.jpg");
 ​
 //2.获取输出流
 ServletOutputStream outputStream = response.getOutputStream();
 ​
 byte[] buff=new byte[1024];
 int len =0;
 while((len=fis.read(buff))!=-1){
     outputStream.write(buff,0,len);
 }

还可以通过IOUtils工具类

 <-- 导入依赖 --></-->
 <dependency>
     <groupId>commons-io</groupId>
     <artifactId>commons-io</artifactId>
     <version>2.6</version>
 </dependency>
 IOUtils.copy(fis,outputStream);


(九)拓展

 servlet获取json数据

 package com.cqut.web;
 ​
 import com.alibaba.fastjson.JSON;
 import com.cqut.pojo.Brand;
 import com.cqut.service.BrandService;
 ​
 import javax.servlet.*;
 import javax.servlet.http.*;
 import javax.servlet.annotation.*;
 import java.io.BufferedReader;
 import java.io.IOException;
 ​
 @WebServlet("/addServlet")
 public class AddServlet extends HttpServlet {
 ​
     private BrandService brandService=new BrandService();
     @Override
     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 ​
         //1.获取页面传递JSON数据
         request.setCharacterEncoding("utf-8");
         BufferedReader reader = request.getReader();
         String jsonString = reader.readLine();
 ​
         //2.JSON转为java对象
         Brand brand = JSON.parseObject(jsonString, Brand.class);
 ​
         //3.调用添加方法
         brandService.add(brand);
 ​
         //4.相应数据
         response.getWriter().write("success");
 ​
     }
 ​
     @Override
     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         this.doGet(request, response);
     }
 }

最后,受限于本人水平,文章中如有疏漏或理解不当之处,欢迎指出交流。  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值