JavaWeb之Servlet是什么以及怎么使用

57 阅读4分钟

一、Servlet是什么?

运行在服务端的Java小程序,是动态资源规范,代码层面上Sevlet就是一个接口。

二、怎么开发一个Servlet(步骤)?

  • 自定义一个类,要继承HttpServlet类
  • 重写service方法,该方法主要就是用于处理用户请求的服务方法
  • HttpServletRequest 代表请求对象,是有请求报文经过tomcat转换而来的,通过该对象可以获取请求中的信息
  • HttpServletResponse 代表响应对象,该对象会被tomcat转换为响应的报文,通过该对象可以设置响应中的信息
  • Servlet对象的生命周期(创建,初始化,处理服务,销毁)是由tomcat管理的,无需我们自己new
  • HttpServletRequest HttpServletResponse 两个对象也是有tomcat负责转换,在调用service方法时传入给我们用的

代码

public class UserServlet  extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求中的参数
        String username = req.getParameter("username");
        if("atguigu".equals(username)){
            //通过响应对象响应信息
            resp.getWriter().write("NO");
        }else{
            resp.getWriter().write("YES");
        }

    }
}

为Servlet配置请求的映射路径

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">
      <!--
      servlet-name 自定义的name值,要求:同一对标签的name要相同
      url-pattern 定义页面的请求地址,注意:请求地址必须使用/开头这里的请求地址是不包含:application context
      -->
    <servlet>
        <!--给UserServlet起一个别名-->
        <servlet-name>userServlet</servlet-name>
        <servlet-class>com.atguigu.servlet.UserServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <!--关联别名和映射路径-->
        <servlet-name>userServlet</servlet-name>
        <!--可以为一个Servlet匹配多个不同的映射路径,但是不同的Servlet不能使用相同的url-pattern-->
        <url-pattern>/userServlet</url-pattern>
    </servlet-mapping>
</web-app>

三、生命周期

  • 测试生命周期时,需要重写init(),service(),destroy()方法
  • servlet生命周期:

第一次请求:

  • 匹配请求地址,找到对应的处理类,判断该类的对象是否存在,不存在的情况下,创建servlet对象。如果存在则直接调用。调取init()进行初始化,仅执行一次
    1. 如果重写了父类的service(),则此时调取service()处理用户名
    2. 没有重写service(),重写了doget()和dopost():父类的service()会根据请求的方法判断是get还是post,如果get,则调取doget(),如果post,调取doPost()

第二次及以后的请求:

  • 直接调取service()方法处理请求
  • 销毁:当服务器关闭时,调取destroy(),销毁servlet对象

注意:实际编写代码只需要重写service()

四、初始化参数

init(SevletConfig config){},需求:在程序中加载一个spring.xml配置文件

局部初始化参数使用:

<servlet>
        <servlet-name>aa</servlet-name>
        <servlet-class>
            com.atguigu.web.Test1Servlet
        </servlet-class>
        <!-- parameter 参数 param-name 自定义的参数名  param-value 参数值  -->
        <init-param>
            <param-name>configname</param-name>
            <param-value>springmvc.xml</param-value>
        </init-param>
</servlet>
@Override
    public void init(ServletConfig config) throws ServletException 
        String configname = config.getInitParameter("configname");
        System.out.println("configname="+configname);
    }

全局初始化参数使用:

<context-param>
    <param-name>encoding</param-name>
    <param-value>utf-8</param-value>
</context-param>
<servlet></servlet>
 System.out.println("------------获取全局初始化参数---------------");
/* ServletContext servletContext = config.getServletContext();
 String encoding = servletContext.getInitParameter("encoding");*/
 String encoding = config.getServletContext().getInitParameter("encoding");
 System.out.println("encoding="+encoding);

load-on-startup标签

<servlet>
    <load-on-startup></load-on-startup>
</servlet>

作用:

  • (1) 可以让指定的servlet在服务器启动时就创建对象并调取init()
  • (2) 取值为正整数,数值越小,优先级越高

五、页面发送请求的方式:

<a href="/application context/自定义的请求">  get
<form action="/application context/自定义的请求">  get/post</form>
window.location="/application context/自定义的请求"  get

通过注解使用

@WebServlet(
        name = "userServlet",
        //value = "/user",
        urlPatterns = {"/userServlet1","/userServlet2","/userServlet"},
        initParams = {@WebInitParam(name = "encoding",value = "UTF-8")},
        loadOnStartup = 6
)
public class UserServlet  extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String encoding = getServletConfig().getInitParameter("encoding");
        System.out.println(encoding);
        // 获取请求中的参数
        String username = req.getParameter("username");
        if("atguigu".equals(username)){
            //通过响应对象响应信息
            resp.getWriter().write("NO");
        }else{
            resp.getWriter().write("YES");
        }
    }
}

上面的代码主要用于替换Servlet配置,注解和xml这两种方式只能二选一,但是要注意我们不能删除web.xml文件

六、HttpServletRequest

  • (1) 请求行

获取请求方式: request.getMethod()

获取请求地址: request,getRequestURI() request,getRequestURL();

  • (2)请求头: request.getHeader(String key)

请求头是什么?类似于下面这种:

image.png

  • (3) 请求体:

String request.getParameter(String key)

Map<String,String[]> request.getParameterMap();

String [] request.getParameterValues();

下面是一个例子来展示他们的用法:

  <!--
    a标签和location发送数据的语法:
        href="/application Context/自定义的请求?key=value&key2=value2&key3=value2"
        第一个参数使用?拼接,第二个及以后的参数使用&拼接
        location="/application Context/自定义的请求?key=value&key2=value2&key3=value2"
  -->
<a href="/testreq?uname=张三&uage=18&usex=男">测试HttpServletRequest</a>
<form action="/testreq" method="post">
    用户名:<input type="text"  name="uname"><br>
    年龄:<input type="text" name="uage"><br>
    性别:<input type="radio" name="usex" value="boy"><input type="radio" name="usex" value="gril"><br>
    爱好:<input type="checkbox" name="like" value="吃饭">吃饭
    <input type="checkbox" name="like" value="睡觉">睡觉
    <input type="checkbox" name="like" value="打豆豆">打豆豆<br>
    <input type="submit">
</form>
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;

@WebServlet("/testreq")
public class RequestServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("requestServlet被执行");
        System.out.println("--------请求行--------------");
        System.out.println("请求方式:"+req.getMethod());
        System.out.println("请求地址:"+req.getRequestURI());// /testreq
        System.out.println("请求地址2:"+req.getRequestURL()); // http://localhost/testreq

        System.out.println("-------------请求头----------------");
        String connection = req.getHeader("Connection");
        String host = req.getHeader("Host");
        String referer = req.getHeader("Referer");
        System.out.println(connection+","+host+","+referer);

        System.out.println("-----------请求体(发送的数据)----------");
        String uname = req.getParameter("uname");
        String usex = req.getParameter("usex");
        String uage = req.getParameter("uage");
        int age=Integer.parseInt(uage);
        System.out.println(uname+","+usex+","+age);
        //将发送的数据封装到Map集合中
        Map<String, String[]> parameterMap = req.getParameterMap();
        Set<String> keySet = parameterMap.keySet();//获取所有的key
        for (String key : keySet) {
            String[] values = parameterMap.get(key);
            System.out.println(key+","+ Arrays.toString(values));
        }
        //获取复选框中的一组数据
        String[] likes = req.getParameterValues("like");
        System.out.println(Arrays.toString(likes));
    }
}

转发:

req.getRequestDispatcher("/testrequest2").forward(req,resp);

七、HttpServletResponse

响应一个字符串给客户端:

//响应一个字符串给客户端
//使用场景:1.返回JSON字符串给客户端  2.返回一段js代码给客户端
//建议:输出语句最好只执行一次
resp.setContentType("text/html;charset=utf-8");//解决响应字符串乱码的问题
resp.getWriter().write("{name:'zhangsan',message:'这是我返回给客户端的字符串'}");
resp.getWriter().write("<script>alert('登录成功');</script>");

响应一个页面或一个新的请求给客户端:

 //响应一个页面给客户端   resp.sendRedirect("跳转的页面路径");
 //resp.sendRedirect("/result/success.html");
 resp.sendRedirect("/testrequest2");

转发和重定向最主要的一个区别是: 转发地址只改变一次,重定向地址会改变两次,所以它们的地址有所差异

八、web乱码问题处理

//1.接收的数据乱码
request.setCharacterEncoding("utf-8");//必须加载service()方法的第一行
//2.响应给客户端字符串时出现乱码
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("");