02、JavaWeb-Servlet

参阅资料推荐

Tomcat--各个目录详解(二) - 啤酒大泡泡 - 博客园
JavaWeb开发重定向与转发_孤夜的博客-CSDN博客

早期的web应用文件是手动往tomcat文件夹下复制的,由于每改动一次代码就得重新往tomcat的目录下部署一次,后来集成到了IDEA中,只需要重新运行程序即可热启动。


 

 

 

 Get请求:

 

 

 

虚拟目录说的是请求转发的时候设置的头
response.setHeader("Location" , " /xxxx/yyyy" ); 

 

 

下面看一个demo带你了解一下tomcat

Servelet demo

 

 

 观察这个demo运行起来的页面

真正部署到tomcat中的是 out---->artifacts---->ServeletPractice_war_exploded

1、路径问题

如果想要访问相应的页面,只需在根路径“/”下访问文件名即可,另外jsp文件就是写html的文件。

http://localhost:port/index.jsp
http://localhost:port/index2.jsp

Web-INF中的文件客户端的浏览器是不能直接访问的

 比如Servelet01.class字节码文件无法访问

http://localhost:8080/WEB-INF/classes/com/test/app/Servelet01.class

http://localhost:8080/WEB-INF/classes/com/test/app/Servelet01

均无法访问

 

2、通过映射的方式访问WEB-INF文件夹下的class字节码文件

客户端的浏览器不能直接访问servlet文件只能通过映射间接访问servlet

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>Servlet001</servlet-name>
        <servlet-class>com.test.app.Servlet01</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Servlet001</servlet-name>
        <url-pattern>/servlet</url-pattern>
    </servlet-mapping>
</web-app>

访问的时候出现了中文乱码

去Servlet01.java文件的service方法中设置它的servletResponse.setContentType("text/html;charset=UTF-8");   //设置编码格式  
servletRequest.setCharacterEncoding("UTF-8");//servlet收到正常编码可以System.out.println()数据

 

 3、带参访问java文件资源

http://localhost:8080/servlet?id=1

在Servlet01.java中添加程序

String id=servletRequest.getParameter("id") ;

 

4、注解方式

@WebServlet("/servlet")

可以达到相同的效果

5、Servlet的生命周期

@WebServlet("/servlet")
public class Servlet01 implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("Serverlet init");
    }

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

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Servlet service");
        servletResponse.setContentType("text/html;charset=UTF-8");
        PrintWriter writer =servletResponse.getWriter();
        writer.write("hello! Client~!");
        writer.write("你好,客户端!");
        String id=servletRequest.getParameter("id");
        writer.write("收到id="+id);
    }

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

    @Override
    public void destroy() {
        System.out.println("Servlet destroy");
    }
}

 init service destroy属于生命周期的方法

创建 使用 回收

c++中是这样的

java 由于有GC机制,你只需要创建对象使用即可,不需要考虑回收

回车

回到idea

多次回车访问http://localhost:8080/servlet 

 当第一次访问的时候会调用init方法,当有了对象后就不会再调用init了,会值接调用service方法

存在对象直接调用,不存在再去创建,有点类似于字符串常量池

只需要一个对象,反复去使用,相当于单例模式

当你关闭程序的时候,会调用destroy释放servlet对象

 6、模拟收到请求后tomcat处理Servlet对象创建的过程

访问http:localhost:8080/servlet的时候
程序会到web.xml一解析拿到全类名,通过反射机制去创建对象

1、当浏览器访问Servlet的时候,Tomcat 会查询当前Servlet的实例化对象是否存在,如果不存在,则通过反射机制动态创建对象,如果存在,直接执行第3步。
2、调用init方法完成初始化操作。
3、调用service方法完成业务逻辑操作。
4、关闭Tomcat时,会调用destory方法,释放当前对象所占用的资源。

Servlet 的生命周期方法:无参构造函数、init、service、destory

1、无参构造函数只调用一次,创建对象。
2、init 只调用一次,初始化对象。
3、service 调用N次,执行业务方法。
4、destory 只调用一次,卸载对象。

下面有一段代码,如果不讲servlet.jar引入到JavaSE环境中,就会报错,无法使用Servlet。
因为在javaSE环境中加载不了Servlet01 实现的那个implements Servlet会报错
所以去tomcat解压的目录下找到servlet.jar复制到当前工程下的lib目录下手动导入一下 

    public static void main(String[] args) {
        // 模拟tomcat创建对象的过程
        // http:localhost:8080/servlet到web.xml一解析拿到全类名,通过反射机制去创建对象
        String str = "com.test.app.Servlet01";
        Class clazz = null;
        try {
            clazz = Class.forName(str);
            Constructor constructor = clazz.getConstructor();
            System.out.println(constructor);//会报错
            // 因为在javaSE环境中加载不了Servlet01 实现的那个implements Servlet报错了
            // 去tomcat解压的目录下找到servlet.jar复制到当前工程下的lib目录下手动导入一下
            // 打印出:public com.test.app.Servlet01()
            Object object= constructor.newInstance();
            System.out.println(object);// com.test.app.Servlet01@43556938
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 

Servlet01.java

package com.test.app;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;


/**
 * @author:
 * @date:2022/1/4
 * @description:
 */
@WebServlet("/servlet")
public class Servlet01 implements Servlet {
    public Servlet01() {
        System.out.println("Servlet01的无参构造函数,在init之前,肯定是先有对象再去初始化");
    }
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("Serverlet init");
    }
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Servlet service");
        servletResponse.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = servletResponse.getWriter();
        writer.write("hello! Client~!");
        writer.write("你好,客户端!");
        String id = servletRequest.getParameter("id");
        writer.write("收到id=" + id);
    }
    @Override
    public String getServletInfo() {
        return null;
    }
    @Override
    public void destroy() {
        System.out.println("Servlet destroy");
    }
    public static void main(String[] args) {
        // 模拟tomcat创建对象的过程
        // http:localhost:8080/servlet到web.xml一解析拿到全类名,通过反射机制去创建对象
        String str = "com.test.app.Servlet01";
        Class clazz = null;
        try {
            clazz = Class.forName(str);
            Constructor constructor = clazz.getConstructor();
            System.out.println(constructor);//会报错
            // 因为在javaSE环境中加载不了Servlet01 实现的那个implements Servlet报错了
            // 去tomcat解压的目录下找到servlet.jar复制到当前工程下的lib目录下手动导入一下
            // 打印出:public com.test.app.Servlet01()
            Object object= constructor.newInstance();
            System.out.println(object);// com.test.app.Servlet01@43556938
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

7、ServletConfig

该接口是用来描述Servlet的基本信息的。
getServletName()返回Servlet的名称,全类名(带着包名的类名)getlnitParameter(String key)
获取init参数的值(web.xml)
getlnitParameterNames()
返回所有的initParamter的name值,一般用作遍历初始化参数
getServletContext()
返回ServletContext对象,它是Serviet 的上 下又,wl 3eive-。
ServletConfig和ServletContext的区别:
ServletConfig作用于某个Servlet实例,每个Servlet都有对应的ServletConfig,ServletContext作用于整个Web应用,一个Web应用对应一个ServletContext,多个Servlet实例对应一个ServletContext。

public interface ServletConfig {
    String getServletName();

    ServletContext getServletContext();

    String getInitParameter(String var1);

    Enumeration<String> getInitParameterNames();
}

获取servletName()

在init方法中,即可
String servletName=servletConfig.getServletName();

从web.xml读取参数

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">
    <!--context的初始化参数配置从这对标签中读取-->
    <context-param>
    <param-name>param0</param-name>
    <param-value>value0</param-value>
    </context-param>

    <servlet>
    <servlet-name>Servlet001</servlet-name>
    <servlet-class>com.test.app.Servlet01</servlet-class>
    <init-param>
    <param-name>userName</param-name>
    <param-value>admin</param-value>
    </init-param>
    </servlet>
    <servlet-mapping>
    <servlet-name>Servlet001</servlet-name>
    <url-pattern>/servlet</url-pattern>
    </servlet-mapping>
    <!--&lt;!&ndash;采用注解的方式映射资源,更加方便快捷&ndash;&gt;-->

</web-app>

servlet.java(因为要从web.xml读取初始化参数,所以一定要把@WebServlet注释掉)

//@WebServlet("/servlet") 由于本次演示在web.xml中定义了此servlet的映射,这里先注释掉,否则重复映射了就。
public class Servlet01 implements Servlet {
    public Servlet01() {
        System.out.println("Servlet01的无参构造函数,在init之前,肯定是先有对象再去初始化");
    }

    public String userName = "";

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        //1
        String servletName = servletConfig.getServletName();// com.test.app.Servlet01
        //2
        //程序加载的时候可以设定一些初始化的参数,和servletRequest.getParameter()不一样,人家是从浏览器地址栏获取参数的。
        //ServletConfig.getInitParameter()是从web.xml获取参数的
        //基于注解取不到这样的东西,另外它用的很少。
        this.userName = servletConfig.getInitParameter("userName");
        //3.1
        Enumeration<String> enStr = servletConfig.getInitParameterNames();//Enumeration有点类似于set集合,只是过时了抛弃了。
        //3.2
        Enumeration enumeration = servletConfig.getInitParameterNames();
        //4
        //servletConfig倾向于Servlet的实例的配置
        //servletContext倾向于全局的一个配置的信息
        ServletContext servletContext = servletConfig.getServletContext();//servlet上下文,整个servlet的管理者
        String servletContextName = servletContext.getServletContextName();
        String contextPath = servletContext.getContextPath();
        String serverInfo = servletContext.getServerInfo();
        // ServletContext同样有getInitParameter和getInitParameterNames
        //web.xml中
        //    <context-param>
        //        <param-name>param0</param-name>
        //        <param-value>value0</param-value>
        //    </context-param>
        // String xxxx = servletContext.getInitParameter("xxxx");
        //Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
        System.out.println(servletContextName+"\n"+contextPath+"\n"+serverInfo);

        System.out.println("Serverlet init");
        System.out.println("\tServerlet Name:" + servletName);//Serverlet Name:Servlet001
        System.out.println("\tServerlet Init Parame:" + this.userName);//Serverlet Init Parame:admin
        System.out.println("\tServerlet ParameterName:" + enStr);
        //遍历3.1 Enumeration<String> enStr
        while (enStr.hasMoreElements()) {
            String element = enStr.nextElement();
            System.out.println("\tServerlet ParameterName:" + element);
            System.out.println("\tServerlet ParameterVlaue:" + servletConfig.getInitParameter(element));
        }
        //遍历3.2 Enumeration enumeration
        while (enumeration.hasMoreElements()) {
            String element = (String) enumeration.nextElement();
            System.out.println("\tServerlet ParameterName:" + element);
            System.out.println("\tServerlet ParameterVlaue:" + servletConfig.getInitParameter(element));
        }
    }
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Servlet service");
        servletResponse.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = servletResponse.getWriter();
        writer.write("hello! Client~!");
        writer.write("你好,客户端!");
        String id = servletRequest.getParameter("id");
        writer.write("收到id=" + id);
    }
    @Override
    public String getServletInfo() {
        return null;
    }
    @Override
    public void destroy() {
        System.out.println("Servlet destroy");
    }
    public static void main(String[] args) {
        // 模拟tomcat创建对象的过程
        // http:localhost:8080/servlet到web.xml一解析拿到全类名,通过反射机制去创建对象
        String str = "com.test.app.Servlet01";
        Class clazz = null;
        try {
            clazz = Class.forName(str);
            Constructor constructor = clazz.getConstructor();
            System.out.println(constructor);//会报错
            // 因为在javaSE环境中加载不了Servlet01 实现的那个implements Servlet报错了
            // 去tomcat解压的目录下找到servlet.jar复制到当前工程下的lib目录下手动导入一下
            // 打印出:public com.test.app.Servlet01()
            Object object = constructor.newInstance();
            System.out.println(object);// com.test.app.Servlet01@43556938
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

问题:

 解决方案:

8、Servlet层次结构

 探究HttpServlet

/**
 * @author:
 * @date:2022/1/5
 * @description: 了解HttpServlet
 */
@WebServlet("/servlet02")
public class Servlet02 extends HttpServlet {
    //顶端接口------------------------>底端接口
    //Servlet---->GenericServlet---->HttpServlet

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //地址栏发送的请求是get请求
        resp.getWriter().write("HtteServlet doGet");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //如果想要客户端发送post请求,要么写一个表单发送,要么用postman等工具发送post请求
        resp.getWriter().write("HtteServlet doPost");
    }
}

 

/**
 * @author:
 * @date:2022/1/5
 * @description: 山寨版的GenericServlet
 *
 *      //顶端接口------------------------>底端接口
 *     //Servlet---->GenericServlet---->HttpServlet
 */
//本类:Servlet03=====手动写了一个GenericServlet,让Servlet04去继承,目的是模拟GenericServlet的用法
//@WebServlet("/servlet03")
public class Servlet03 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 {
        //在客户端中,无论get请求还是post请求
        //http://localhost:port/servlet03
        //请求的响应都是 hello world,它不会区分post请求和get请求
        servletResponse.getWriter().write("hello world");
    }

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

    @Override
    public void destroy() {

    }
}

/**
 * @author:
 * @date:2022/1/5
 * @description: 山寨版的HttpServlet
 * 继承自己写的山寨版的GenericServlet,哪个有用你就重写哪一个方法,不用向实现Servlet一样重写那么多方法,而且还可以实现
 * //顶端接口------------------------>底端接口
 * //Servlet---->GenericServlet---->HttpServlet
 */
@WebServlet("/servlet04")
public class Servlet04 extends Servlet03 {
    /**
     * @param: [servletRequest, servletResponse]
     * @return: void
     * @description: 山寨版的HttpServlet
     * 本类的重点是重写service,证明继承了GenericServlet类后就不需要重写那么多方法了
     * 当然这个GenericServlet是手动模拟的一个Servlet03作用和GenericServlet一样。
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        //获取请求类型
        String method = request.getMethod();//会返回GET或者POST
        System.out.println(method);
        switch (method) {
            case "GET":
                this.doGet(request, response);
                break;
            case "POST":
                this.doPost(request, response);
                break;
        }
    }

    //这里是让父类做个分发
    public void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {

    }

    //这里是让父类做个分发
    public void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {

    }


}
/**
 * @author:
 * @date:2022/1/5
 * @description: 继承山寨版的HttpServlet,同样可以实现doGet和doPost
 */
@WebServlet("/servlet05")
public class Servlet05 extends Servlet04 {

    @Override
    public void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
        httpServletResponse.setContentType("text/html;charset=UTF-8");
        httpServletResponse.getWriter().write("山寨版HttpServlet doGet");
    }

    @Override
    public void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
        httpServletResponse.setContentType("text/html;charset=UTF-8");
        httpServletResponse.getWriter().write("山寨版HttpServlet doPost");
    }
}

Get请求 

Post请求

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值