[Java]JavaWeb学习笔记(动力节点老杜2022)【Javaweb+MVC架构模式完结】(四)

简介: [Java]JavaWeb学习笔记(动力节点老杜2022)【Javaweb+MVC架构模式完结】(四)

🥽 模板方法设计模式

  • 什么是设计模式?
  • 某个问题的固定的解决方案。(可以被重复使用。)
  • 你知道哪些设计模式?
  • GoF设计模式:
  • 通常我们所说的23种设计模式。(Gang of Four:4人组提出的设计模式)
  • 单例模式
  • 工厂模式
  • 代理模式
  • 门面模式
  • 责任链设计模式
  • 观察者模式
  • 模板方法设计模式
  • JavaEE设计模式:
  • DAO
  • DTO
  • VO
  • PO
  • pojo
  • 什么是模板方法设计模式?
  • 在模板类的模板方法当中定义核心算法骨架,具体的实现步骤可以延迟到子类当中完成。
  • 模板类通常是一个抽象类,模板类当中的模板方法定义核心算法,这个方法通常是final的(但也可以不是final的)
  • 模板类当中的抽象方法就是不确定实现的方法,这个不确定怎么实现的事儿交给子类去做。
package com.bjpowernode.template1;
public class Student {
    /**
     * 这个方法描述学生的一天
     */
    public void day(){
        // 和Teacher的算法相同。
        qiChuang();
        xiShu();
        chiZaoCan();
        doSome();
        chiWanFan();
        shuiJiao();
    }
    public void qiChuang(){
        System.out.println("起床");
    }
    public void xiShu(){
        System.out.println("洗漱");
    }
    public void chiZaoCan(){
        System.out.println("吃早餐");
    }
    public void doSome(){
        System.out.println("学生上学,学习");
    }
    public void chiWanFan(){
        System.out.println("吃晚饭");
    }
    public void shuiJiao(){
        System.out.println("睡觉");
    }
}
package com.bjpowernode.template1;
/**
 * 存在的问题:
 *      第一:算法没有得到重复的使用。
 *      第二:代码没有得到复用。
 */
public class Teacher {
    /**
     * 这个方法描述老师的一天
     */
    public void day(){
        // 和Student的算法相同。
        qiChuang();
        xiShu();
        chiZaoCan();
        doSome();
        chiWanFan();
        shuiJiao();
    }
    public void qiChuang(){
        System.out.println("起床");
    }
    public void xiShu(){
        System.out.println("洗漱");
    }
    public void chiZaoCan(){
        System.out.println("吃早餐");
    }
    public void doSome(){
        System.out.println("老师正在课堂上授课,教授学生知识");
    }
    public void chiWanFan(){
        System.out.println("吃晚饭");
    }
    public void shuiJiao(){
        System.out.println("睡觉");
    }
}
package com.bjpowernode.template2;
/**
 * Teacher和Student都是Person
 * 1. Person就是模板方法设计模式当中的模板类。
 * 2. day()方法就是模板方法设计模式当中的模板方法。
 */
public abstract class Person { // 模板类通常是抽象类。
    // 模板方法
    // 添加了final之后,这个方法无法被覆盖,这样核心的算法也可以得到保护。
    // 模板方法定义核心的算法骨架,具体的实现步骤可以延迟到子类当中去实现。
    // 核心算法一方面是得到了保护,不能被改变。另外一方面就是算法得到了重复使用。
    // 另外代码也得到了服用,因为算法中某些步骤的代码是固定的。这些固定的代码不会随着子类的变化而变换,这一部分代码可以写到模板类当中。
    public final void day(){
        // 第一步
        qiChuang();
        // 第二步
        xiShu();
        // 第三步
        chiZaoCan();
        // 第四步
        doSome();
        // 第五步
        chiWanFan();
        // 第六步
        shuiJiao();
    }
    // 其中的某些步骤,不会随着子类的变化而变化,这些代码可以写到父类中,得到代码复用。
    public void qiChuang(){
        System.out.println("起床");
    }
    public void xiShu(){
        System.out.println("洗漱");
    }
    public void chiZaoCan(){
        System.out.println("吃早餐");
    }
    // 这一步是要做,但是具体这一步怎么做,子类说了算。
    public abstract void doSome();
    public void chiWanFan(){
        System.out.println("吃晚饭");
    }
    public void shuiJiao(){
        System.out.println("睡觉");
    }
}
package com.bjpowernode.template2;
public class Student extends Person {
    public void doSome(){
        System.out.println("学生上学,学习");
    }
}
package com.bjpowernode.template2;
public class Teacher extends Person{
    public void doSome(){
        System.out.println("老师正在课堂上授课,教授学生知识");
    }
}

🥽 HttpServlet源码分析

  • HttpServlet类是专门为HTTP协议准备的。比GenericServlet更加适合HTTP协议下的开发。
  • HttpServlet在哪个包下?
  • jakarta.servlet.http.HttpServlet
  • 到目前为止我们接触了servlet规范中哪些接口?
  • jakarta.servlet.Servlet 核心接口(接口)
  • jakarta.servlet.ServletConfig Servlet配置信息接口(接口)
  • jakarta.servlet.ServletContext Servlet上下文接口(接口)
  • jakarta.servlet.ServletRequest Servlet请求接口(接口)
  • jakarta.servlet.ServletResponse Servlet响应接口(接口)
  • jakarta.servlet.ServletException Servlet异常(类)
  • jakarta.servlet.GenericServlet 标准通用的Servlet类(抽象类)
  • http包下都有哪些类和接口呢?jakarta.servlet.http.*;
  • jakarta.servlet.http.HttpServlet (HTTP协议专用的Servlet类,抽象类)
  • jakarta.servlet.http.HttpServletRequest (HTTP协议专用的请求对象)
  • jakarta.servlet.http.HttpServletResponse (HTTP协议专用的响应对象)
  • HttpServletRequest对象中封装了什么信息?
  • HttpServletRequest,简称request对象。
  • HttpServletRequest中封装了请求协议的全部内容。
  • Tomcat服务器(WEB服务器)将“请求协议”中的数据全部解析出来,然后将这些数据全部封装到request对象当中了。
  • 也就是说,我们只要面向HttpServletRequest,就可以获取请求协议中的数据。
  • HttpServletResponse对象是专门用来响应HTTP协议到浏览器的。
  • 回忆Servlet生命周期?
  • 用户第一次请求
  • Tomcat服务器通过反射机制,调用无参数构造方法。创建Servlet对象。(web.xml文件中配置的Servlet类对应的对象。)
  • Tomcat服务器调用Servlet对象的init方法完成初始化。
  • Tomcat服务器调用Servlet对象的service方法处理请求。
  • 用户第二次请求
  • Tomcat服务器调用Servlet对象的service方法处理请求。
  • 用户第三次请求
  • Tomcat服务器调用Servlet对象的service方法处理请求。
  • Tomcat服务器调用Servlet对象的service方法处理请求。
  • 服务器关闭
  • Tomcat服务器调用Servlet对象的destroy方法,做销毁之前的准备工作。
  • Tomcat服务器销毁Servlet对象。
  • HttpServlet源码分析:
public class HelloServlet extends HttpServlet {
  // 用户第一次请求,创建HelloServlet对象的时候,会执行这个无参数构造方法。
  public HelloServlet() {
    }
    //override 重写 doGet方法
    //override 重写 doPost方法
}
public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {
  // 用户第一次请求的时候,HelloServlet对象第一次被创建之后,这个init方法会执行。
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
  // 用户第一次请求的时候,带有参数的init(ServletConfig config)执行之后,会执行这个没有参数的init()
  public void init() throws ServletException {
        // NOOP by default
    }
}
// HttpServlet模板类。
public abstract class HttpServlet extends GenericServlet {
    // 用户发送第一次请求的时候这个service会执行
    // 用户发送第N次请求的时候,这个service方法还是会执行。
    // 用户只要发送一次请求,这个service方法就会执行一次。
    @Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {
        HttpServletRequest  request;
        HttpServletResponse response;
        try {
            // 将ServletRequest和ServletResponse向下转型为带有Http的HttpServletRequest和HttpServletResponse
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }
        // 调用重载的service方法。
        service(request, response);
    }
    // 这个service方法的两个参数都是带有Http的。
    // 这个service是一个模板方法。
    // 在该方法中定义核心算法骨架,具体的实现步骤延迟到子类中去完成。
    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        // 获取请求方式
        // 这个请求方式最终可能是:""
        // 注意:request.getMethod()方法获取的是请求方式,可能是七种之一:
        // GET POST PUT DELETE HEAD OPTIONS TRACE
        String method = req.getMethod();
        // 如果请求方式是GET请求,则执行doGet方法。
        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {
                    // Invalid date header - proceed as if none was set
                    ifModifiedSince = -1;
                }
                if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }
        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);
        } else if (method.equals(METHOD_POST)) {
            // 如果请求方式是POST请求,则执行doPost方法。
            doPost(req, resp);
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException{
        // 报405错误
        String msg = lStrings.getString("http.method_get_not_supported");
        sendMethodNotAllowed(req, resp, msg);
    }
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        // 报405错误
        String msg = lStrings.getString("http.method_post_not_supported");
        sendMethodNotAllowed(req, resp, msg);
    }
}
/*
通过以上源代码分析:
  假设前端发送的请求是get请求,后端程序员重写的方法是doPost,子类没有实现doGet方法,会执行父类的doGet方法,父类的doGet方法会报405错误
  假设前端发送的请求是post请求,后端程序员重写的方法是doGet
  会发生什么呢?
    发生405这样的一个错误。
    405表示前端的错误,发送的请求方式不对。和服务器不一致。不是服务器需要的请求方式。
  通过以上源代码可以知道:只要HttpServlet类中的doGet方法或doPost方法执行了,必然405.
怎么避免405的错误呢?
  后端重写了doGet方法,前端一定要发get请求。
  后端重写了doPost方法,前端一定要发post请求。
  这样可以避免405错误。
  这种前端到底需要发什么样的请求,其实应该后端说了算。后端让发什么方式,前端就得发什么方式。
有的人,你会看到为了避免405错误,在Servlet类当中,将doGet和doPost方法都进行了重写。
这样,确实可以避免405的发生,但是不建议,405错误还是有用的。该报错的时候就应该让他报错。
如果你要是同时重写了doGet和doPost,那还不如你直接重写service方法好了。这样代码还能
少写一点。
*/
  • 我们编写的HelloServlet直接继承HttpServlet,直接重写HttpServlet类中的service()方法行吗?
  • 可以,只不过你享受不到405错误。享受不到HTTP协议专属的东西。
  • 到今天我们终于得到了最终的一个Servlet类的开发步骤:
  • 第一步:编写一个Servlet类,直接继承HttpServlet
  • 第二步:重写doGet方法或者重写doPost方法,到底重写谁,javaweb程序员说了算。
  • 第三步:将Servlet类配置到web.xml文件当中。
  • 第四步:准备前端的页面(form表单),form表单中指定请求路径即可。

🥽 关于一个web站点的欢迎页面

  • 什么是一个web站点的欢迎页面?
  • 对于一个webapp来说,我们是可以设置它的欢迎页面的。
  • 设置了欢迎页面之后,当你访问这个webapp的时候,或者访问这个web站点的时候,没有指定任何“资源路径”,这个时候会默认访问你的欢迎页面。
  • 我们一般的访问方式是:
  • http://localhost:8080/servlet06/login.html 这种方式是指定了要访问的就是login.html资源。
  • 如果我们访问的方式是:
  • http://localhost:8080/servlet06 如果我们访问的就是这个站点,没有指定具体的资源路径。它默认会访问谁呢?
  • 默认会访问你设置的欢迎页面。
  • 怎么设置欢迎页面呢?
  • 第一步:我在IDEA工具的web目录下新建了一个文件login.html
  • 第二步:在web.xml文件中进行了以下的配置
<welcome-file-list>
        <welcome-file>login.html</welcome-file>
    </welcome-file-list>
  • 注意:设置欢迎页面的时候,这个路径不需要以“/”开始。并且这个路径默认是从webapp的根下开始查找
  • 第三步:启动服务器,浏览器地址栏输入地址
  • http://localhost:8080/servlet07
  • 如果在webapp的根下新建一个目录,目录中再给一个文件,那么这个欢迎页该如何设置呢?
  • 在webapp根下新建page1
  • 在page1下新建page2目录
  • 在page2目录下新建page.html页面
  • 在web.xml文件中应该这样配置
<welcome-file-list>
    <welcome-file>page1/page2/page.html</welcome-file>
</welcome-file-list>
  • 注意:路径不需要以“/”开始,并且路径默认从webapp的根下开始找
  • 一个webapp是可以设置多个欢迎页面的
<welcome-file-list>
    <welcome-file>page1/page2/page.html</welcome-file>
    <welcome-file>login.html</welcome-file>
</welcome-file-list>
  • 注意:越靠上的优先级越高。找不到的继续向下找
  • 你有没有注意一件事:当我的文件名设置为index.html的时候,不需要在web.xml文件中进行配置欢迎页面。这是为什么?
  • 这是因为小猫咪Tomcat服务器已经提前配置好了。
  • 实际上配置欢迎页面有两个地方可以配置:
  • 一个是在webapp内部的web.xml文件中。(在这个地方配置的属于局部配置)
  • 一个是在CATALINA_HOME/conf/web.xml文件中进行配置。(在这个地方配置的属于全局配置)
<welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>
  • Tomcat服务器的全局欢迎页面是:index.html index.htm index.jsp。如果你一个web站点没有设置局部的欢迎页面,Tomcat服务器就会以index.html index.htm index.jsp作为一个web站点的欢迎页面。
  • 注意原则:局部优先原则。(就近原则)
  • 欢迎页可以是一个Servlet吗?
  • 当然可以。
  • 你不要多想,欢迎页就是一个资源,既然是一个资源,那么可以是静态资源,也可以是动态资源。
  • 静态资源:index.html welcome.html …
  • 动态资源:Servlet类。
  • 步骤:
  • 第一步:写一个Servlet
public class WelcomeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.print("<h1>welcome to bjpowernode!</h1>");
    }
}
  • 第二步:在web.xml文件中配置servlet
<servlet>
        <servlet-name>welcomeServlet</servlet-name>
        <servlet-class>com.bjpowernode.javaweb.servlet.WelcomeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>welcomeServlet</servlet-name>
        <url-pattern>/fdsa/fds/a/fds/af/ds/af/dsafdsafdsa</url-pattern>
    </servlet-mapping>
  • 第三步:在web.xml文件中配置欢迎页
<welcome-file-list>
        <welcome-file>fdsa/fds/a/fds/af/ds/af/dsafdsafdsa</welcome-file>
    </welcome-file-list>

🥽 关于WEB-INF目录

  • 在WEB-INF目录下新建了一个文件:welcome.html
  • 打开浏览器访问:http://localhost:8080/servlet07/WEB-INF/welcome.html 出现了404错误。
  • 注意:放在WEB-INF目录下的资源是受保护的在浏览器上不能够通过路径直接访问。所以像HTML、CSS、JS、image等静态资源一定要放到WEB-INF目录之外。

🥽 HttpServletRequest接口详解

  • HttpServletRequest是一个接口,全限定名称:jakarta.servlet.http.HttpServletRequest
  • HttpServletRequest接口是Servlet规范中的一员。
  • HttpServletRequest接口的父接口:ServletRequest
public interface HttpServletRequest extends ServletRequest {}
  • HttpServletRequest接口的实现类谁写的? HttpServletRequest对象是谁给创建的?
  • 通过测试:org.apache.catalina.connector.RequestFacade 实现了 HttpServletRequest接口
public class RequestFacade implements HttpServletRequest {}
  • 测试结果说明:Tomcat服务器(WEB服务器、WEB容器)实现了HttpServletRequest接口,还是说明了Tomcat服务器实现了Servlet规范。而对于我们javaweb程序员来说,实际上不需要关心这个,我们只需要面向接口编程即可。我们关心的是HttpServletRequest接口中有哪些方法,这些方法可以完成什么功能!!!!
  • HttpServletRequest对象中都有什么信息?都包装了什么信息?
  • HttpServletRequest对象是Tomcat服务器负责创建的。这个对象中封装了什么信息?封装了HTTP的请求协议。
  • 实际上是用户发送请求的时候,遵循了HTTP协议,发送的是HTTP的请求协议,Tomcat服务器将HTTP协议中的信息以及数据全部解析出来,然后Tomcat服务器把这些信息封装到HttpServletRequest对象当中,传给了我们javaweb程序员。
  • javaweb程序员面向HttpServletRequest接口编程,调用方法就可以获取到请求的信息了。
  • request和response对象的生命周期?
  • request对象和response对象,一个是请求对象,一个是响应对象。这两个对象只在当前请求中有效。
  • 一次请求对应一个request。
  • 两次请求则对应两个request。
  • HttpServletRequest接口中有哪些常用的方法?
  • 怎么获取前端浏览器用户提交的数据?
Map<String,String[]> getParameterMap() 这个是获取Map
Enumeration<String> getParameterNames() 这个是获取Map集合中所有的key
String[] getParameterValues(String name) 根据key获取Map集合的value
String getParameter(String name)  根据key获取value这个一维数组当中的第一个元素。这个方法最常用。
// 以上的4个方法,和获取用户提交的数据有关系。
  • 思考:如果是你,前端的form表单提交了数据之后,你准备怎么存储这些数据,你准备采用什么样的数据结构去存储这些数据呢?
  • 前端提交的数据格式:username=abc&userpwd=111&aihao=s&aihao=d&aihao=tt
  • 我会采用Map集合来存储:
Map<String,String>
    key存储String
    value存储String
    这种想法对吗?不对。
    如果采用以上的数据结构存储会发现key重复的时候value覆盖。
    key         value
    ---------------------
    username    abc
    userpwd     111
    aihao       s
    aihao       d
    aihao       tt
    这样是不行的,因为map的key不能重复。
Map<String, String[]>
    key存储String
    value存储String[]
    key       value
    -------------------------------
    username    {"abc"}
    userpwd     {"111"}
    aihao     {"s","d","tt"}
  • 注意:前端表单提交数据的时候,假设提交了120这样的“数字”,其实是以字符串"120"的方式提交的,所以服务器端获取到的一定是一个字符串的"120",而不是一个数字。(前端永远提交的是字符串,后端获取的也永远是字符串。)
  • 手工开发一个webapp。测试HttpServletRequest接口中的相关方法。
  • 先测试了4个常用的方法,获取请求参数的四个方法。
Map<String,String[]> parameterMap = request.getParameterMap();
  Enumeration<String> names = request.getParameterNames();
  String[] values = request.getParameterValues("name");
  String value = request.getParameter("name");
package com.bjpowernode.javaweb.servlet;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.*;
import java.util.*;
/*
username=zhangsan&userpwd=123&interest=s&interest=d
Map<String,String[]>
key       value
---------------------------
"username"    {"zhangsan"}
"userpwd"   {"123"}
"interest"    {"s", "d"}
总结一下:request接口中四个非常重要的方法。
  Map<String,String[]> parameterMap = request.getParameterMap();
  Enumeration<String> names = request.getParameterNames();
  String[] values = request.getParameterValues("name");
  String value = request.getParameter("name");
*/
public class RequestTestServlet extends HttpServlet{
  public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws IOException,ServletException{
    // 面向接口编程:HttpServletRequest接口。
    // 获取前端提交的数据
    // 前端会提交什么数据呢?
    // username=zhangsan&userpwd=123&interest=s&interest=d
    // 以上的数据会被小猫咪封装到request对象中。
    // 获取参数Map集合
    Map<String,String[]> parameterMap = request.getParameterMap();
    // 遍历Map集合(获取Map集合中所有的key,遍历)
    Set<String> keys = parameterMap.keySet();
    Iterator<String> it = keys.iterator();
    while(it.hasNext()){
      String key = it.next();
      //System.out.println(key);
      // 通过key获取value
      String[] values = parameterMap.get(key);
      /*
        username=[Ljava.lang.String;@7cce40b4
        userpwd=[Ljava.lang.String;@7453f0b9
        interest=[Ljava.lang.String;@4063ebb5
      */
      //System.out.println(key + "=" + values);
      // 遍历一维数组
      System.out.print(key + "=");
      for(String value : values){
        System.out.print(value + ",");
      }
      // 换行
      System.out.println();
    }
    // 直接通过getParameterNames()这个方法,可以直接获取这个Map集合的所有key
    Enumeration<String> names = request.getParameterNames();
    while(names.hasMoreElements()){
      String name = names.nextElement();
      System.out.println(name);
    }
    // 直接通过name获取value这个一维数组。
    String[] usernames = request.getParameterValues("username");
    String[] userpwds = request.getParameterValues("userpwd");
    String[] interests = request.getParameterValues("interest");
    // 遍历一维数组
    for(String username : usernames){
      System.out.println(username);
    }
    for(String userpwd : userpwds){
      System.out.println(userpwd);
    }
    for(String interest : interests){
      System.out.println(interest);
    }
    // 通过name获取value这个一维数组的第一个元素
    // 这个方法使用最多,因为这个一维数组中一般只有一个元素。
    String username = request.getParameter("username");
    String userpwd = request.getParameter("userpwd");
    //String interest = request.getParameter("interest");
    // 既然是checkbox,调用方法:request.getParameterValues("interest")
    String[] interests2 = request.getParameterValues("interest");
    // 获取的都是一维数组当中的第一个元素。
    System.out.println(username);
    System.out.println(userpwd);
    //System.out.println(interest);
    for(String interest : interests2){
      System.out.println(interest);
    }
  }
}
  • request对象实际上又称为“请求域”对象。
  • 应用域对象是什么?
  • ServletContext (Servlet上下文对象。)
  • 什么情况下会考虑向ServletContext这个应用域当中绑定数据呢?
  • 第一:所有用户共享的数据。
  • 第二:这个共享的数据量很小。
  • 第三:这个共享的数据很少的修改操作。
  • 在以上三个条件都满足的情况下,使用这个应用域对象,可以大大提高我们程序执行效率。
  • 实际上向应用域当中绑定数据,就相当于把数据放到了缓存(Cache)当中,然后用户访问的时候直接从缓存中取,减少IO的操作,大大提升系统的性能,所以缓存技术是提高系统性能的重要手段。
  • 你见过哪些缓存技术呢?
  • 字符串常量池
  • 整数型常量池 [-128~127],但凡是在这个范围当中的Integer对象不再创建新对象,直接从这个整数型常量池中获取。大大提升系统性能。
  • 数据库连接池(提前创建好N个连接对象,将连接对象放到集合当中,使用连接对象的时候,直接从缓存中拿。省去了连接对象的创建过程。效率提升。)
  • 线程池(Tomcat服务器就是支持多线程的。所谓的线程池就是提前先创建好N个线程对象,将线程对象存储到集合中,然后用户请求过来之后,直接从线程池中获取线程对象,直接拿来用。提升系统性能)
  • 后期你还会学习更多的缓存技术,例如:redis、mongoDB…
  • ServletContext当中有三个操作域的方法:
void setAttribute(String name, Object obj); // 向域当中绑定数据。
Object getAttribute(String name); // 从域当中根据name获取数据。
void removeAttribute(String name); // 将域当中绑定的数据移除
// 以上的操作类似于Map集合的操作。
Map<String, Object> map;
map.put("name", obj); // 向map集合中放key和value
Object obj = map.get("name"); // 通过map集合的key获取value
map.remove("name"); // 通过Map集合的key删除key和value这个键值对。
  • “请求域”对象
  • “请求域”对象要比“应用域”对象范围小很多。生命周期短很多。请求域只在一次请求内有效。
  • 一个请求对象request对应一个请求域对象。一次请求结束之后,这个请求域就销毁了。
  • 请求域对象也有这三个方法:
void setAttribute(String name, Object obj); // 向域当中绑定数据。
Object getAttribute(String name); // 从域当中根据name获取数据。
void removeAttribute(String name); // 将域当中绑定的数据移除
  • 请求域和应用域的选用原则?
  • 尽量使用小的域对象,因为小的域对象占用的资源较少。
  • 跳转
  • 转发(一次请求)
// 这样做可以吗?
  // 在AServlet当中new一个BServlet对象,然后调用BServlet对象的doGet方法,把request对象传过去。
  // 这个代码虽然可以实现功能,但是Servlet对象不能自己由程序员来new。自己new的Servlet对象生命周期不受Tomcat服务器的管理。
  /*BServlet bServlet = new BServlet();
  bServlet.doGet(request, response);*/
  // 使用Servlet当中的转发机制。
  // 执行了AServlet之后,跳转到BServlet。(这个资源跳转可以使用转发机制来完成。)
  // 怎么转发?代码怎么写?
  // 第一步:获取请求转发器对象
  // 相当于把"/b"这个路径包装到请求转发器当中,实际上是把下一个跳转的资源的路径告知给Tomcat服务器了。
  RequestDispatcher dispatcher = request.getRequestDispatcher("/b");
  // 第二步:调用请求转发器RequestDispatcher的forward方法。进行转发。
  // 转发的时候:这两个参数很重要。request和response都是要传递给下一个资源的。
  dispatcher.forward(request, response);
  // 一行代码搞定转发。
  request.getRequestDispatcher("/b").forward(request, response);
  • 两个Servlet怎么共享数据?
  • 将数据放到ServletContext应用域当中,当然是可以的,但是应用域范围太大,占用资源太多。不建议使用。
  • 可以将数据放到request域当中,然后AServlet转发到BServlet,保证AServlet和BServlet在同一次请求当中,这样就可以做到两个Servlet,或者多个Servlet共享同一份数据。
  • 转发的下一个资源必须是一个Servlet吗?
  • 不一定,只要是Tomcat服务器当中的合法资源,都是可以转发的。例如:html…
  • 注意:转发的时候,路径的写法要注意,转发的路径以“/”开始,不加项目名。
// 转发到一个Servlet,也可以转发到一个HTML,只要是WEB容器当中的合法资源即可。
request.getRequestDispatcher("/test.html").forward(request, response);
  • 关于request对象中两个非常容易混淆的方法:
// uri?username=zhangsan&userpwd=123&sex=1
String username = request.getParameter("username");
// 之前一定是执行过:request.setAttribute("name", new Object())
Object obj = request.getAttribute("name");
// 以上两个方法的区别是什么?
// 第一个方法:获取的是用户在浏览器上提交的数据。
// 第二个方法:获取的是请求域当中绑定的数据。
  • HttpServletRequest接口的其他常用方法:
// 获取客户端的IP地址
String remoteAddr = request.getRemoteAddr();
// request.getRemoteHost(); 获取远程主机地址
// request.getRemotePort(); 获取端口
// get请求在请求行上提交数据。
// post请求在请求体中提交数据。
// 设置请求体的字符集。(显然这个方法是处理POST请求的乱码问题。这种方式并不能解决get请求的乱码问题。)
// Tomcat10之后,request请求体当中的字符集默认就是UTF-8,不需要设置字符集,不会出现乱码问题。
// Tomcat9前(包括9在内),如果前端请求体提交的是中文,后端获取之后出现乱码,怎么解决这个乱码?执行以下代码。
request.setCharacterEncoding("UTF-8");
// 在Tomcat9之前(包括9),响应中文也是有乱码的,怎么解决这个响应的乱码?
response.setContentType("text/html;charset=UTF-8");
// 在Tomcat10之后,包括10在内,响应中文的时候就不在出现乱码问题了。以上代码就不需要设置UTF-8了。
// 注意一个细节
// 在Tomcat10包括10在内之后的版本,中文将不再出现乱码。(这也体现了中文地位的提升。)
// get请求乱码问题怎么解决?
// get请求发送的时候,数据是在请求行上提交的,不是在请求体当中提交的。
// get请求乱码怎么解决
// 方案:修改CATALINA_HOME/conf/server.xml配置文件
<Connector URIEncoding="UTF-8" />
// 注意:从Tomcat8之后,URIEncoding的默认值就是UTF-8,所以GET请求也没有乱码问题了。
// 获取应用的根路径
String contextPath = request.getContextPath();
// 获取请求方式
String method = request.getMethod();
// 获取请求的URI
String uri = request.getRequestURI();  // /aaa/testRequest
// 获取servlet path,不带项目名
String servletPath = request.getServletPath(); //   /testRequest


相关文章
|
6月前
|
JavaScript Java 大数据
基于JavaWeb的销售管理系统设计系统
本系统基于Java、MySQL、Spring Boot与Vue.js技术,构建高效、可扩展的销售管理平台,实现客户、订单、数据可视化等全流程自动化管理,提升企业运营效率与决策能力。
|
9月前
|
Java API 微服务
2025 年 Java 从入门到精通学习笔记全新版
《Java学习笔记:从入门到精通(2025更新版)》是一本全面覆盖Java开发核心技能的指南,适合零基础到高级开发者。内容包括Java基础(如开发环境配置、核心语法增强)、面向对象编程(密封类、接口增强)、进阶技术(虚拟线程、结构化并发、向量API)、实用类库与框架(HTTP客户端、Spring Boot)、微服务与云原生(容器化、Kubernetes)、响应式编程(Reactor、WebFlux)、函数式编程(Stream API)、测试技术(JUnit 5、Mockito)、数据持久化(JPA、R2DBC)以及实战项目(Todo应用)。
475 5
|
12月前
|
存储 Java
# 【Java全栈学习笔记-U1-day02】变量+数据类型+运算符
本篇笔记主要围绕Java全栈学习的第二天内容展开,涵盖了变量、数据类型、运算符以及Scanner类的应用。首先介绍了变量的概念与命名规范,以及如何定义和使用变量;接着详细讲解了Java中的基本数据类型,包括整型、浮点型、字符型、布尔型等,并通过实例演示了数据类型的运用。随后,深入探讨了各类运算符(赋值、算术、关系、逻辑)及其优先级,帮助理解表达式的构成。最后,介绍了如何利用Scanner类实现用户输入功能,并通过多个综合示例(如计算圆面积、购物打折、变量交换及银行利息计算)巩固所学知识。完成相关作业将进一步加深对这些基础概念的理解与实践能力。
228 13
|
6月前
|
小程序 Java 知识图谱
Java 学习笔记 —— BMI & BMR 计算器
这是一个使用 Java 编写的 BMI 与 BMR 计算器小程序,可输入年龄、性别、身高和体重,计算身体质量指数(BMI)和基础代谢率(BMR),并输出健康评估结果。通过该项目,掌握了 Java 的输入处理、数据验证、条件判断、数学运算及格式化输出等基础知识,是 Java 初学者的理想练习项目。
|
6月前
|
Java
Java 数组学习笔记
本文整理Java数组常用操作:遍历、求和、查找、最值及二维数组行求和等典型练习,涵盖静态初始化、元素翻倍、去极值求平均等实例,帮助掌握数组基础与应用。
|
6月前
|
前端开发 Java 开发者
MVC 架构模式技术详解与实践
本文档旨在全面解析软件工程中经典且至关重要的 MVC(Model-View-Controller) 架构模式。内容将深入探讨 MVC 的核心思想、三大组件的职责与交互关系、其优势与劣势,并重点分析其在现代 Web 开发中的具体实现,特别是以 Spring MVC 框架为例,详解其请求处理流程、核心组件及基本开发实践。通过本文档,读者将能够深刻理解 MVC 的设计哲学,并掌握基于该模式进行 Web 应用开发的能力。
1137 1
|
8月前
|
SQL 前端开发 Java
JavaWeb 学习日记案例详解及 javaweb 完整项目案例实战指南
本文介绍了一个基于Spring Boot的JavaWeb企业员工管理系统完整案例,涵盖部门管理、员工管理、登录、异常处理、事务管理及AOP等核心功能实现,结合CSDN相关技术文章,提供详细技术方案与应用实例,适合JavaWeb开发者学习与参考。
512 0
|
11月前
|
Java 数据库连接 应用服务中间件
JavaWeb CRUD 与分页系统架构学习教程
本教程详细讲解了如何使用 Java Web 技术构建一个带有 CRUD 和分页功能的应用程序。以产品信息管理为例,采用 MVC 架构设计,涵盖 Servlet、JSP、JDBC/MyBatis 等技术。内容包括基础知识介绍、项目结构划分、数据库连接配置、DAO 层实现、Service 层设计、Servlet 控制层编写、JSP 前端展示以及分页功能的实现。同时涉及日志配置和 Tomcat 部署运行。通过分层开发,确保代码清晰、职责分明,便于维护和扩展。适合初学者掌握 Java Web 开发全流程,并为学习更高级框架奠定基础。
308 0
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
570 0
|
存储 开发框架 前端开发
[回馈]ASP.NET Core MVC开发实战之商城系统(五)
经过一段时间的准备,新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始,在之前的文章中,讲解了商城系统的整体功能设计,页面布局设计,环境搭建,系统配置,及首页【商品类型,banner条,友情链接,降价促销,新品爆款】,商品列表页面,商品详情等功能的开发,今天继续讲解购物车功能开发,仅供学习分享使用,如有不足之处,还请指正。
409 0