J2EE 01(Servlet、JSP)


J2EE 01

目录
  • J2EE 01
    • 一、Servlet(一)
      • 2. Tomcat服务器
      • 3. Servlet接口
      • 4. GenericServlet抽象类
      • 6. Servlet应用类中使用配置信息两种方式
      • 7. GET和POST请求
      • 8. 接收并处理浏览器请求的相关接口
      • 9. 向客户端发送响应的相关接口
      • 10. ServletConfig接口
      • 11. ServletContext接口
      • 12. Servlet应用类的几种路径总结
      • 13. Servlet应用的生命周期
      • 14. request中attribute和parameter
      • 15. request的生命周期
    • 二、Servlet(二)
      • 1. Servlet和JDBC案例
      • 2. 重定向和转发
      • 3. Servlet线程安全
      • 4. 状态管理
      • 5. Cookie
      • 6. Session
    • 三、JSP(Java Server Pages)
      • 1. JSP概述
      • 2. JSP语法
      • 3. JSP内置对象
      • 4. JavaBean组件
      • 5. MVC设计模式

一、Servlet(一)

1. HTTP协议

  • HTTP概述

    一般浏览器通过输入域名/IP:端口号访问网页,采用的是HTTP协议,默认的是80端口,在浏览器输入地址时这个端口号可以省略

    www.baidu.combaidu.com相当于对应一个IP,浏览器中加端口号访问baidu.com:80

  • HTTP请求格式

    客户端发送一个HTTP请求到服务器的请求消息

    主要包括:请求行、请求头、空白行和请求体

    请求行中包含了:请求类型、请求的路径、协议的版本

    请求头中信息为key-value,用来说明服务器要使用的附加信息:主机信息(值为地址:端口号)、请求长度、浏览器相关信息

    请求体也叫请求数据(一般POST请求数据在请求体中),可以添加任意的其他数据,即使请求数据为空也必须有请求头的空行

  • HTTP响应格式

    通常情况下服务器接收并处理客户端发过来的请求后会返回一个HTTP的响应消息

    主要包括:响应行、响应头、空白行和响应体

    响应行中包括了:协议版本、状态码(200 成功 404 路径错误 500 服务错误)、状态信息(如OK)

    响应头中信息为key-value,用来说明客户端要使用的一些附加信息:响应内容类型、响应内容长度、日期

    响应体用来服务器返回给客户端的文本信息,即使响应体为空也必须有响应头的空行,响应体可以是由HTML标签组成的内容

2. Tomcat服务器

  • Tomcat概述

    Tomcat 服务器是一个开源的轻量级Web应用服务器,在中小型系统和并发量小的场合下被普遍使用,是开发和调试Servlet、JSP 程序的首选

    Tomcat默认的配置中端口号是8080

  • 安装方式:解压即可

  • 目录结构

    • bin:启动和关闭的批处理文件在此文件夹下

    • conf:常用的配置文件server.xmltomcat-users.xml

    • webapps:存放应用程序的资源目录,当Tomcat启动时会去加载该目录下的应用程序

      到该目录下手动放一个应用文件夹,在浏览器中就可以通过localhost:8080/应用文件夹/路径来访问里面的资源

      在浏览器中访问localhost:8080就会默认访问该目录下的ROOT文件夹的index.jsp

  • 启动和关闭

    • 手动方式:

      安装目录下bin文件夹下批处理文件startup.batshutdown.bat

      检查本地Tomcat服务器已启动:访问localhost:8080,进入Tomcat页面

    • CMD方式:

      需要将Tomcat安装目录添加到环境变量,添加好后直接CMD中直接输入startupshutdown

    • 启动信息乱码的处理方式

      在conf下的配置文件中修改指定的字符集为UTF-8

      或者在IDEA中.vmoptions文件中加入一行字符集配置(同时解决Localhost Log、Catalina Log、Server console乱码)


  • 相关配置

    • 配置端口号(端口号范围0-65535,避开一些默认端口)、设置域名/IP、默认加载的项目、请求编码等

      在安装目录下的conf文件夹中server.xml中Connector标签中修改

    • 配置管理Tomcat服务器的用户与权限

      在安装目录下的conf文件夹中tomcat-users.xml中添加role和user标签

      localhost:8080中的manager app可以登录管理员界面,使用添加的用户信息登录

3. Servlet接口

  • Servlet(Server Applet)是Java Servlet的简称,称为小服务程序服务连接器,Servlet就是运行在服务器上的Java类

  • 作用:Servlet用来完成B/S架构下客户端请求的响应处理,也就是交互式地浏览和生成数据,生成动态Web内容

  • 开发者一般写这种的Servlet应用就是Servlet接口的实现类

    实现类需要重写Servlet中的几个抽象方法:

    void init(ServletConfig config)

    void service(ServletRequest req, ServletResponse res)

    ServletConfig getServletConfig()

    String getServletInfo()

    void destroy()

  • 示例Code

    public class HelloServlet 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{
            System.out.println("接收到了浏览器的请求并做出了响应!");
        }
    
        @Override
        public String getServletInfo() {
            return null;
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

4. GenericServlet抽象类

  • 开发者一般写这种的Servlet应用就是这个抽象类的子类;GenericServlet抽象类是Servlet接口的实现类

  • 使用GenericServlet抽象类的子类,只需要重写唯一的一个抽象方法service

    abstract void service(ServletRequest req, ServletResponse res)

    这个抽象service方法的作用:由servlet容器调用允许servlet响应请求

  • 示例Code

    public class HelloServlet2 extends GenericServlet {
        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
            System.out.println("继承GenericServlet类的方式来创建Servlet");
        }
    }
    

5. HttpServlet抽象类

  • 开发者一般写这种的Servlet应用就是这个抽象类的子类(比上面两种更常用);HttpServlet抽象类是GenericServlet抽象类的子类

    HttpServlet抽象类没有抽象方法,其中重写了GenericServlet里的service方法,还重载了这个方法其中参数换为了HttpServletRequest、HttpServletResponse

    HttpServlet抽象类没有抽象方法原因:为了避免创建一个没有业务功能的HttpServlet对象,只提供开发者用来继承HttpServlet进行开发

  • 使用HttpServlet抽象类的子类,一般重写doGet和doPost方法

    一般不推荐重写这个抽象类中service方法来判断请求类型,因为在这个类中已经使用service定义了根据请求决定调用doGet方法还是doPost方法

    一般在doGet方法中写doPost方法的调用,在doPost方法中写具体的处理流程,这样统一使用doPost中的处理方法

    @WebServlet(name = "HelloServlet4", urlPatterns = "/hello4")
    public class HelloServlet4 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("Post请求方式...");
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("Get请求方式...");
            this.doPost(request, response);
        }
    
       /* @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("原来使用注解可以如此潇洒...");
            String method = req.getMethod();
            System.out.println("获取到的请求方式为:" + method);
            if ("get".equalsIgnoreCase(method)) {
                doGet(req, resp);
            }
            if ("post".equalsIgnoreCase(method)) {
                doPost(req, resp);
            }
        }*/
    }
    
  • HttpServlet抽象类常用方法

    void doGet(HttpServletRequest req, HttpServletResponse resp)

    void doPost(HttpServletRequest req, HttpServletResponse resp)

    void init() :该方法继承GenericServlet中的空参方法,GenericServlet中也有重写Servlet接口中带参的版本

    void service(HttpServletRequest req, HttpServletResponse resp)

    void destroy() :该方法继承GenericServlet中的空参方法

6. Servlet应用类中使用配置信息两种方式

  • 配置信息包括:该servlet应用的别名,该servlet应用的ServletPath(urlPatterns属性或url-pattern标签)

    urlPatterns路径中必须以/开头

    别名的作用:将ServletPath与servlet应用关联

  • 具体方式:

    1. 使用项目目录下src/main/webapp/WEB-INF/web.xml

      定义两个父标签同时包含子标签:

      • 配置:别名、当前项目模块java文件夹下的全类名

      • 映射:别名、当前Servlet应用所在的路径ServletPath

    2. 使用@WebServlet注解,对两个参数赋值:别名name、当前Servlet应用所在的路径ServletPathurlPatterns

    修改配置信息(指上面配置文件方法,注解方法重新部署即可)后需要重启服务器Restart server

    修改servlet应用类中其他内容或HTML、JSP,不用重启服务器,只需重新部署Redeploy

  • 新建Servlet应用类可以选择是否添加注解

    选择添加注解默认给的属性是name和value,需要自行添加urlPatterns属性和属性值

    Servlet别名、ServletPath、Servlet应用类名这三者可以起不同的名称,互不影响


  • 创建Servlet应用类后并配置好别名和ServletPath,仍然无法获取请求,尝试将当前项目模块重新打包热部署到服务器上

    • war模式这种可以称之为是发布模式,也就是先打成war包,再发布

    • war exploded模式是直接把文件夹、jsp页面 、classes等移到Tomcat 部署文件夹里面,进行加载部署

      因此这种方式支持热部署,一般在开发的时候也是用这种方式

    • 在平时开发的时候,使用热部署的话,应该对Tomcat进行相应的设置,这样的话修改的JSP界面什么的东西才可以及时的显示出来




7. GET和POST请求

  • 发出GET请求的主要方式:
    • 使用 link 标签引入 css 样式
    • 其他几种方式
      1. 在浏览器输入URL按回车

        (可选)URL后面加?key=value为请求添加参数,多个键值用&连接,在Servlet应用中使用request.getParameter("key")获取对应的value

      2. 点击超链接

      3. 点击submit按钮,提交

        表单

(可选)GET请求会将请求数据(参数)添加到请求URL地址的后面,只能提交少量的数据、不安全

  • 发出POST请求的主要方式:
    • 点击submit按钮,提交method属性为POST的表单

请求参数获取到的默认是全大写字符串,比较时注意使用大写或用equalsIgnoreCase方法

POST请求会将请求数据(参数)添加到HTTP协议体中,可提交大量数据、安全性好

8. 接收并处理浏览器请求的相关接口

  • ServletRequest接口

    • 接口中方法常用于表单中不同数据的获取
  • HttpServletRequest接口

    • javax.servlet.http.HttpServletRequest接口是ServletRequest接口的子接口,主要用于提供HTTP请求信息的功能
    • 不同于表单数据,在发送HTTP请求时,HTTP请求头直接由浏览器设置;可直接通过HttpServletRequest对象提供的一系列get方法获取请求头数据
  • Servlet应用中使用request对象接收时,中文乱码处理方法

    • 获取的POST请求内容乱码处理方法

      setCharacterEncoding方法

      必须在调用request.getxxx()之前设置

    • 获取的GET请求内容乱码处理方法(通常是因为Tomcat版本过低导致)

      将字符串按默认的解码方式解码为字节数组(.getBytes("字符集")),再按指定的字符集编码成字符串(String构造方法,传入编码字符集)

  • 示例Code

    public class ParameterServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 6.设置请求信息中的编码方式为utf-8来解决乱码问题
            request.setCharacterEncoding("utf-8");
    
            // 1.获取指定参数名称对应的参数值并打印
            String name = request.getParameter("name");
            System.out.println("获取到的姓名为:" + name);
            String[] hobbies = request.getParameterValues("hobby");
            System.out.print("获取到的爱好有:");
            for (String ts : hobbies) {
                System.out.print(ts + " ");
            }
            System.out.println();
    
            System.out.println("-------------------------------------------------------");
            // 2.获取所有参数的名称
            Enumeration parameterNames = request.getParameterNames();
            System.out.print("获取到的所有参数名称为:");
            while (parameterNames.hasMoreElements()) {
                System.out.print(parameterNames.nextElement() + " ");
            }
            System.out.println();
    
            System.out.println("-------------------------------------------------------");
            // 3.获取请求参数名和对应值的第二种方式
            Map parameterMap = request.getParameterMap();
            // 使用Map集合中所有的键值对组成Set集合
            Set> entries = parameterMap.entrySet();
            // 遍历Set集合
            for (Map.Entry me : entries) {
                System.out.print(me.getKey() + "对应的数值有:");
                for (String ts : me.getValue()) {
                    System.out.print(ts + " ");
                }
                System.out.println();
            }
    
            System.out.println("-------------------------------------------------------");
            // 4.获取客户端请求的其它信息
            System.out.println("发送请求的客户端IP地址为:" + request.getRemoteAddr());
            System.out.println("发送请求的客户端端口号为:" + request.getRemotePort());
            System.out.println("请求资源的路径为:" + request.getRequestURI());
            System.out.println("请求资源的完整路径为:" + request.getRequestURL());
            System.out.println("请求方式为:" + request.getMethod());
            System.out.println("请求的附带参数为:" + request.getQueryString());
            System.out.println("请求的Servlet路径为:" + request.getServletPath());
    
            System.out.println("-------------------------------------------------------");
            // 5.向浏览器发出响应数据
            // 获取响应数据的默认编码方式
            String characterEncoding = response.getCharacterEncoding();
            System.out.println("服务器响应数据的默认编码方式为:" + characterEncoding); // ISO-8859-1
            // 设置服务器和浏览器的编码方式以及文本类型
            response.setContentType("text/html;charset=UTF-8");
            PrintWriter writer = response.getWriter();
            //writer.write("I Received!");
            //writer.write("我接收到了!");
            Random ra = new Random();
            int num = ra.nextInt(100) + 1;
            writer.write("

    " + num + "

    "); System.out.println("服务器发送数据成功!"); writer.close(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }

9. 向客户端发送响应的相关接口

  • ServletResponse接口

    • 通常使用打印流向客户端发送响应

      获取打印流PrintWriter getWriter()

      发送完后关闭打印流

    • 设置和获取响应的编码方式相关方法

      设置响应的编码示例(在发送响应之前,设置发送到客户端响应的内容类型)

      response.setContentType("text/html;charset=utf-8");
      
  • HttpServletResponse接口

    • javax.servlet.http.HttpServletResponse接口继承ServletResponse接口,以便在发送响应时提供特定于HTTP的功能
    • void sendRedirect(String location)指定重定向位置URL向客户端发送临时重定向响应

10. ServletConfig接口

  • 用于描述Servlet本身的相关配置信息,在初始化期间用于将信息传递给Servlet配置对象

  • 使用方式:在init方法中使用ServletConfig对象(init方法的形参)调用相关方法

  • 示例Code

     
    
        actionservlet
        com.example.demo01.ActionServlet
        
        
             
            userName 
            
            admin 
        
        
             
            password 
            
            123456 
        
    
    
    public class ConfigServlet implements Servlet {
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {
            System.out.println("初始化操作执行了...");
            System.out.println("Servlet的别名是:" + servletConfig.getServletName()); // ConfigServlet
    
            System.out.println("-----------------------------------------------");
            // 获取配置文件中的初始化参数信息
            String userName = servletConfig.getInitParameter("userName");
            System.out.println("获取到的初始化用户名为:" + userName);
            // 获取所有配置参数的名称
            Enumeration initParameterNames = servletConfig.getInitParameterNames();
            while (initParameterNames.hasMoreElements()) {
                System.out.println("初始化参数名为:" + initParameterNames.nextElement());
            }
    
            System.out.println("-----------------------------------------------");
            // 获取ServletContext接口的引用
            ServletContext servletContext = servletConfig.getServletContext();
            System.out.println("获取到的ServletContext引用为:" + servletContext);
        }
    
        @Override
        public ServletConfig getServletConfig() {
            return null;
        }
    
        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException{
    
        }
    
        @Override
        public String getServletInfo() {
            return null;
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

11. ServletContext接口

  • 服务器容器在启动时会为每个项目创建唯一的一个ServletContext对象,用于实现多个Servlet之间的信息共享和通信

  • 获取ServletContext对象的两种方法:

    • 使用ServletConfig对象调用方法ServletContext getServletContext()来获取
    • 在Servlet应用类中通过this.getServletContext()这样调用方法可以获得ServletContext对象(this可以省略)
  • ServletContext对象常用方法

  • 示例Code

    public class ContextServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 1.配置参数的获取
            ServletContext servletContext = getServletConfig().getServletContext();
            Enumeration initParameterNames = servletContext.getInitParameterNames();
            while (initParameterNames.hasMoreElements()) {
                String s = initParameterNames.nextElement();
                System.out.println( s + "对应的值为:" + servletContext.getInitParameter(s));
            }
    
            System.out.println("----------------------------------------------------------");
            // 2.相关路径的获取
            // 本质上就是获取工程路径    /工程名
            String contextPath = servletContext.getContextPath();
            System.out.println("获取上下文关联的路径信息为:" + contextPath); // /task01_demo02
    
            // / 在服务器被解析为: http://ip地址:端口号/工程名  获取实际路径信息
            // 获取到的是部署工程路径信息   对应  当前工程中的web目录
            String realPath = servletContext.getRealPath("/");
            // C:\Users\Marz\IdeaProjects\javaweb\out\artifacts\task01_demo02_war_exploded\
            System.out.println("获取到的实际路径信息为:" + realPath);
    
            System.out.println("----------------------------------------------------------");
            // 3.设置和获取属性信息
            servletContext.setAttribute("key", "value");
            Object key = servletContext.getAttribute("key");
            System.out.println("根据参数指定的属性名获取到的属性值为:" + key); // value
            servletContext.removeAttribute("key");
            key = servletContext.getAttribute("key");
            System.out.println("根据参数指定的属性名获取到的属性值为:" + key); // null
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request, response);
        }
    }
    

12. Servlet应用类的几种路径总结

  • 虚拟路径的实际路径

    ServletContext对象通过String getRealPath(String path)方法获取的实际路径,这个也是Servlet应用在硬盘中的路径,

    带盘符的绝对路径

  • 上下文关联的主路径

    ServletContext对象通过getContextPath()方法获取,是工程部署路径(/工程名),相对路径

    也可以通过request对象方法request.getContextPath()获取ContextPath(也叫工程路径)

  • ServletPath

    当前Servlet应用所在的路径,格式:/Servlet应用的别名,相对路径

    通过HttpServletRequest对象调用getServletPath获取

  • RequestURI

    请求的资源路径信息,格式:/工程名/Servlet应用的别名,相对路径

  • RequestURL

    请求的完整路径信息,格式:浏览器中输入访问当前Servlet应用的路径,绝对路径

    如:http://localhost:8080/ServletStudy/hs4

13. Servlet应用的生命周期

  • 示例Code

    public class HelloServlet3 extends HttpServlet {
    
        public HelloServlet3() {
            System.out.println("构造方法调用了");
        }
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("这是采用继承HttpServlet类的方式创建,以后的开发中推荐该方式!");
        }
    
        @Override
        public void destroy() {
            System.out.println("销毁操作开始喽...");
        }
    
        @Override
        public void init() throws ServletException {
            System.out.println("初始化操作开始喽...");
        }
    }
    

    启动Tomcat服务器后以上几个方法不会被调用,在浏览器中输入RequestURL后,才开始依次调用构造方法、init方法、service方法;

    构造方法可以创建Servlet应用类的实例,有了Servlet应用类的实例对象,立即调用init进行初始化

    浏览器中再次输入RequestURL后,只有service方法被调用;

    调用service的次数同request的次数

    关闭服务器后,控制台输出查看到destroy方法被调用了一次;

    Web应用被卸载前调用该方法来释放当前占用的资源

14. request中attribute和parameter

  • 来源不同:参数(parameter)是从客户端(浏览器)中由用户提供的,若是GET方法是从URL中提供的,若是POST方法是从请求体(request body)中提供的;属性(attribute)是服务器端的组件(JSP或者Servlet)利用requst.setAttribute()设置的
    操作不同:参数(parameter)的值只能读取不能修改,读取可以使用request.getParameter()读取;属性(attribute)的值既可以读取亦可以修改,读取可以使用request.getAttribute(),设置可使用request.setAttribute(),
    数据类型不同:参数(parameter)不管前台传来的值语义是什么,在服务器获取时都以String类型看待,并且客户端的参数值只能是简单类型的值,不能是复杂类型,比如一个对象。 属性(attribute)的值可以是任意一个Object类型。

  • 共同点:

    二者的值都被封装在request对象中

15. request的生命周期

  • JSP发送请求到应用程序(一般会是servlet),应用程序接收请求之后,这个request就被销毁

二、Servlet(二)

1. Servlet和JDBC案例

  • 项目文件目录

  • 注册页面的实现(src/main/webapp/register.html

    action属性设定表单提交后跳转到register(这是一个ServletPath不带/)

    提交表单的参数:username、password

    
    
    
        
        Title
    
    
        
            

    用户名:

       密码:

  • src/main/java/com/example/project01_servletjdbc/model文件夹中创建User类

    public class User {
        private int id;
        private String userName;
        private String password;
    
        public User() {
        }
    
        public User(String userName, String password) {
            this.userName = userName;
            this.password = password;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "userName='" + userName + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }
    
  • 准备DBUtils工具类(src/main/java/com/example/project01_servletjdbc/util)

    DBUtils工具类作用:提供数据库连接和关闭连接的静态方法

    需要在src/main/webapp/WEB-INF中创建lib文件夹放入JDBC驱动jar包

    public class DbUtil {
        private static String jdbcName;   // 用于描述驱动信息
        private static String dbUrl;      // 用于描述URL信息
        private static String dbUserName; // 用户描述用户名信息
        private static String dbPassword; // 用户描述密码信息
    
        // 进行静态成员的初始化操作
        static {
            jdbcName = "com.mysql.jdbc.Driver";
            dbUrl = "jdbc:mysql://localhost:3306/db_web";
            dbUserName = "root";
            dbPassword = "123456";
            try {
                Class.forName(jdbcName);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 获取连接
         * @return
         * @throws SQLException
         */
        public static Connection getConnection() throws SQLException {
            Connection con = DriverManager.getConnection(dbUrl, dbUserName, dbPassword);
            return con;
        }
    
        /**
         * 关闭连接
         * @param con
         * @throws SQLException
         */
        public static void closeConnection(Connection con, PreparedStatement psts) throws SQLException {
            if (null != con) {
                con.close();
            }
            if (null != psts) {
                psts.close();
            }
        }
    }
    
  • 使用DBUtil实现UserDao类中的数据库操作相关方法(src/main/java/com/example/project01_servletjdbc/dao)

    UserDao类中createUser方法的操作:

    • 连接到数据库

    • 执行指定的SQL,返回执行结果(成功:影响的行数)

    • 断开连接

    • 返回执行结果(失败:0)

    public class UserDao {
    
        public int createUser(User user) {
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            try {
                // 1.获取连接
                connection = DbUtil.getConnection();
                // 2.准备sql语句
                String sql = "insert into t_user values(null, ?, ?)";
                // 3.获取PrepareStatement类型的引用
                preparedStatement = connection.prepareStatement(sql);
                // 4.向问号所占的位置设置数据
                preparedStatement.setString(1, user.getUserName());
                preparedStatement.setString(2, user.getPassword());
                // 5.执行sql语句
                int row = preparedStatement.executeUpdate();
                return row; // 执行成功
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                // 6.关闭资源
                try {
                    DbUtil.closeConnection(connection, preparedStatement);
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return 0; // 执行失败
        }
    }
    
  • 表单提交后调用Servlet应用类获取请求的参数值,将获取到的参数值打包成对象,再进行数据库中的处理,根据处理结果向浏览器发送响应

    获取的请求参数是表单中子标签的name属性对应的属性值

    创建src/main/webapp/WEB-INF/web.xml文件,设定Servlet别名和ServletPath

    <?xml version="1.0" encoding="UTF-8"?>
    
        
            RegisterServlet
            com.example.project01_servletjdbc.servlet.RegisterServlet
        
    
        
            RegisterServlet
            /register
        
    
    

    src/main/java/com/example/project01_servletjdbc/servlet文件夹下创建Servlet应用类

    doPost方法中的主要操作:

    • 通过request获取指定参数名的值
    • 使用model中类的带参构造创建对象(将获取到的参数值传入)
    • 创建UserDao对象,调用其中的createUser方法(传入刚才创建的对象)
    • 根据createUser方法的返回值判断,根据判断结果发送响应信息
    public class RegisterServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 1.获取请求对象中保存的用户名和密码信息
            String userName = request.getParameter("userName");
            System.out.println("获取到的用户名为:" + userName);
            String password = request.getParameter("password");
            System.out.println("获取到的密码为:" + password);
            // 2.将接受到的用户名和密码信息打包成用户对象交给DAO层进行处理
            User user = new User(userName, password);
            UserDao userDao = new UserDao();
            int res = userDao.createUser(user);
            // 3.将处理结果响应到浏览器
            response.setContentType("text/html;charset=utf-8");
            PrintWriter writer = response.getWriter();
            if (1 == res) {
                System.out.println("注册成功!");
                writer.write("

    注册成功!

    "); } else { writer.write("

    注册失败!

    "); } writer.close(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
  • 改进:使用DAO工厂类:封装了对象的创建细节,为调用者提供符合要求的对象

2. 重定向和转发

  • redirect

    • 重定向:服务器将浏览器的请求接收后向浏览器发送新的地址,浏览器按这个新的地址,重新发送请求

    • 重定向的实现:在Serlvet应用类中调用HttpServletResponse对象的方法void sendRedirect(String location)

    • 重定向的URL可以是其它项目工程,也可以是指定的域名(字符串中开头需要加协议类型)

      重定向之后,浏览器地址栏的URL会发生改变,可以跳转到当前项目下的其他资源,也可以跳转到指定的域名

    • 重定向过程中会将前面Request对象销毁,然后创建一个新的Request对象(两次请求)

    • 示例Code

      public class RedirectServlet extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
              System.out.println("接收到了浏览器的请求...");
              // 重定向,也就是给浏览器发送一个新的位置
              //response.sendRedirect("target.html");
              response.sendRedirect("https://www.baidu.com/index.php?tn=monline_3_dg");
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              this.doPost(request, response);
          }
      }
      
  • forward

    • 转发:首先需要有两个Servlet应用,让web组件将任务(ServletPath地址)转交给另一个web组件(当前工程下的),帮这个转交对象进行req和res的调用

    • 实现方法:

      让web组件调用getRequestDispatcher(String ServletPath)方法,获取RequestDispatcher对象

      使用这个对象调用void forward(ServletRequest request, ServletResponse response)

      getRequestDispatcher的传参不能是其他URL如域名,只能是当前项目中的Servlet应用的ServletPath

    • request对象的其他常用方法

      请求对象中可以存储键值对

      Object getAttribute(String name)通过键值对的key获取value

      oid setAttribute(String name,Object o)设置键值对,key为String类型

    • 示例Code

      public class ForwardServlet extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              System.out.println("接收到了浏览器的请求...");
              // 向request对象中设置属性信息
              request.setAttribute("key1", "value1");
              // 转发,也就是让Web组件将任务转交给另外一个Web组件
              //RequestDispatcher requestDispatcher = request.getRequestDispatcher("/targetServlet");
              RequestDispatcher requestDispatcher = request.getRequestDispatcher("https://www.baidu.com/index.php?tn=monline_3_dg");
              requestDispatcher.forward(request, response);
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              this.doPost(request, response);
          }
      }
      
      public class TargetServlet extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              System.out.println("转发过来了...");
              // 获取request对象中的属性值判断是否共享
              Object key1 = request.getAttribute("key1");
              System.out.println("获取到的属性值为:" + key1); // value1
              // 通过打印流向页面写入转发成功的信息
              response.setContentType("text/html;charset=utf-8");
              response.getWriter().write("

      转发成功!

      "); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
  • 对比

    • 转发之后浏览器地址栏的URL不会发生改变,但是URL中的ServletPath根据情况会改变
    • 重定向可以理解为是在客户端上的跳转,转发可以理解为是在服务器中的跳转

3. Servlet线程安全

  • 浏览器地址栏中输入参数,服务器端获取参数的示例, HTML使用iframe标签

    
    
    
        
        Servlet线程安全的测试
    
    
    


  • 两种解决方法

    • 使用同步代码块(尽量避免,可能会资源开销过大)
    • 使用局部变量代替成员变量(推荐解决方法)
  • 示例Code

    @WebServlet(name = "ThreadServlet", urlPatterns = "/thread")
    public class ThreadServlet extends HttpServlet {
    
        //private String name; // 准备一个成员变量,作为共享资源
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //synchronized (this) {
                // 1.获取request对象中名字为name的参数数值并赋值给成员变量name
                String name = request.getParameter("name");
                System.out.println("获取到的name数值为:" + name);
                // 2.睡眠5秒钟
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 3.使用打印流将成员变量name的数值发送给浏览器
                PrintWriter writer = response.getWriter();
                writer.write("

    " + name + "

    "); writer.close(); //} } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }

4. 状态管理

  • HTTP是无状态的协议:一旦服务器响应完客户的请求之后,就断开连接,而同一个客户的下一次请求又会重新建立网络连接,把浏览器与服务器之间多次交互作为一个整体,将多次交互所涉及的数据保存下来,即状态管理
  • 状态管理的技术:
    • Cookie:将状态保存在客户端
    • Session:将状态保存在服务器端
  • Cookie:这里表示客户端以键值对的形式(相同路径下类似于Map集合name不能重复,value可重复,不同路径可以添加相同的name)进行保存信息的技术

  • 浏览器在请求当前项目下的某个Servlet应用(如只调用getCookies方法),浏览器就向服务器发送请求(请求头中内容是上一次修改的Cookie信息),此时响应头中不含Cookie信息,浏览器文件中存储的Cookie信息不发生改变仍是上一次的

  • 浏览器在请求当前项目下的某个Servlet应用(包含addCookie方法的应用)时,浏览器就向服务器发送请求(请求头中Cookie内容带有上一次修改的Cookie信息), 服务器将新设置的Cookie数据放入带有Set-Cookie属性的响应头给浏览器,然后浏览器会将这些数据以文本文件的方式保存起来(相同路径下, 两次name相同进行value的替换,name不同进行存储)

  • 在Servlet应用类中创建Cookie对象并添加到响应信息中:

    在服务器端的Servlet应用中,创建Cookie对象,将对象传参给response的调用方法addCookie中

    @WebServlet(name = "CookieServlet", urlPatterns = "/cs")
    public class CookieServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 1.测试一下浏览器的请求是否到达
            System.out.println("看看有没有执行到这里哦!");
            // 2.创建Cookie对象并添加到响应信息中
            Cookie cookie = new Cookie("name", "zhangfei");
            response.addCookie(cookie);
            System.out.println("创建Cookie成功!");
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request, response);
        }
    }
    

    下图中,请求头信息保存的是上一次的Cookie信息,响应头保存的Set-Cookie消息是在Servlet应用类中用addCookie添加的

    下图中,浏览器中存储的Cookie信息已经发生了变化

  • 获取浏览器中保存上一次的Cookie信息

    调用getCookies方法不会为响应头添加Set-Cookie消息

    @WebServlet(name = "CookieServlet2", urlPatterns = "/cs2")
    public class CookieServlet2 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 1.获取客户端发来的Cookie信息并打印出来
            Cookie[] cookies = request.getCookies();
            System.out.println("获取到的Cookie信息有:");
            for (Cookie tc : cookies) {
                System.out.println(tc.getName() + "对应的值为:" + tc.getValue());
            }
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request, response);
        }
    }
    
  • 对浏览器中保存上一次的Cookie信息值进行设置

    该操作中调用了addCookie方法同样也会为响应头添加Set-Cookie消息

    @WebServlet(name = "CookieServlet3", urlPatterns = "/cs3")
    public class CookieServlet3 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 1.获取客户端发来的Cookie信息并打印出来
            Cookie[] cookies = request.getCookies();
            for (Cookie tc : cookies) {
                // 2.当获取到的Cookie对象的名字为name时,将对应的数值修改为guanyu并添加到响应信息中
                if ("name".equalsIgnoreCase(tc.getName())) {
                    tc.setValue("guanyu");
                    response.addCookie(tc);
                    break;
                }
            }
            System.out.println("修改Cookie信息成功!");
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request, response);
        }
    }
    
  • 生命周期

    • 默认情况下,浏览器会将Cookie信息保存在内存中,只要浏览器关闭,Cookie信息就会移出(浏览器存储文件没有上一次设置的Cookie信息,请求头中Cookie内容也不带有上一次修改的Cookie信息)

    • 如果希望关闭浏览器一段时间后再打开浏览器Cookie信息仍有效,可以通过Cookie类的成员方法实现

      int getMaxAge()

      void setMaxAge(int expiry)

      @WebServlet(name = "CookieServlet4", urlPatterns = "/cookie4")
      public class CookieServlet4 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 1.创建Cookie信息
            Cookie cookie = new Cookie("name", "liubei");
            // 2.获取Cookie信息的默认使用期限
            int maxAge = cookie.getMaxAge();
            System.out.println("该Cookie的默认使用期限是:" + maxAge);
            // 3.修改Cookie信息的使用期限
            // 正数表示在指定的秒数后失效   负数表示浏览器关闭后失效(不设置默认值是-1)   0表示马上失效
            //cookie.setMaxAge(0);
            cookie.setMaxAge(60*10);
            // 4.添加到响应信息中
            response.addCookie(cookie);
            System.out.println("设置Cookie的生命周期成功!");
        }
      
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request, response);
        }
      }
      
  • Cookie的路径问题

    • 访问的请求地址必须符合Cookie的路径或者其子路径时,浏览器才会发送Cookie信息

    • 浏览器在访问服务器时,会比较Cookie的路径与请求路径是否匹配,只有匹配的Cookie才会发送给服务器

    • Cookie的默认添加路径

      request.getContextPath()获取ContextPath(也叫工程路径),是Cookie未改地址的默认添加路径

    • 示例Code

      @WebServlet(name = "CookieServlet5", urlPatterns = "/cookie5")
      public class CookieServlet5 extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              // 1.创建Cookie对象并指定数值
              //Cookie cookie = new Cookie("name", "zhaoyun");
              Cookie cookie = new Cookie("name", "huangzhong");
              // 3.修改Cookie的路径信息
              cookie.setPath(request.getContextPath() + "/hello");
              // 2.添加到响应信息中
              response.addCookie(cookie);
              System.out.println("设置Cookie路径成功!");
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              this.doPost(request, response);
          }
      }
      

      不同路径下可以存放相同name的Cookie信息

6. Session

  • 浏览器访问服务器时,服务器会为每一个浏览器都在服务器端的内存中分配一个空间,用于创建一个Session对象,该对象有一个id属性且该值唯一,该属性称为SessionId,并且服务器会将这个SessionId以Cookie方式发送给浏览器存储,浏览器再次访问服务器时会将SessionId发送给服务器,服务器可以依据SessionId查找相对应的Session对象

    相当于是把SessionId当作是Cookie中的一个name,对应的value是SessionId值

  • 创建Session对象、判断Session、从Session对象中获取Session编号

    HttpSession getSession() 返回此请求关联的当前Session,若此请求没有则创建一个

    @WebServlet(name = "SessionServlet", urlPatterns = "/session")
    public class SessionServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 1.调用getSession方法获取或者创建Session对象
            HttpSession session = request.getSession();
            // 2.判断该Session对象是否为新建的对象
            System.out.println(session.isNew()? "新创建的Session对象": "已有的Session对象");
            // 3.获取编号并打印
            String id = session.getId();
            System.out.println("获取到的Session编号为:" + id);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request, response);
        }
    }
    
  • Session实现属性的设置和获取

    使用javax.servlet.http.HttpSession接口的成员方法实现属性的管理

    @WebServlet(name = "SessionServlet2", urlPatterns = "/session2")
    public class SessionServlet2 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            HttpSession session = request.getSession();
            // 1.设置属性名和属性值
            session.setAttribute("name", "machao");
            // 2.获取指定属性名对应的属性值
            System.out.println("获取到的属性值为:" + session.getAttribute("name")); // machao
            // 3.删除指定的属性名
            session.removeAttribute("name");
            // 4.获取指定属性名对应的属性值
            System.out.println("获取到的属性值为:" + session.getAttribute("name")); // null
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request, response);
        }
    }
    
  • 生命周期

    • 生命周期概述

      为了节省服务器内存空间资源,服务器会将空闲时间过长的Session对象自动清除掉,服务器默认的超时限制一般是30分钟

    • 修改失效时间的方式:

      • 修改配置文件

        在web.xml文件中修改失效时间,将session-config标签下的session-timeout标签的内容进行修改

      • 调用方法

        @WebServlet(name = "SessionServlet3", urlPatterns = "/session3")
        public class SessionServlet3 extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                // 1.获取Session对象
                HttpSession session = request.getSession();
                // 2.获取对象的默认失效时间并打印
                int maxInactiveInterval = session.getMaxInactiveInterval();
                System.out.println("获取到的失效时间为:" + maxInactiveInterval); // 1800
                // 3.修改实现时间后重新获取并打印
                session.setMaxInactiveInterval(1200);
                maxInactiveInterval = session.getMaxInactiveInterval();
                System.out.println("获取到的失效时间为:" + maxInactiveInterval); // 1200
            }
        
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doPost(request, response);
            }
        }
        

三、JSP(Java Server Pages)

1. JSP概述

  • JSP:是一种特殊的Servlet,经过编译器后还是Servlet的内容,可以发送大量数据同时处理逻辑
  • 使用场景:跟Servlet一样可以动态生成HTML响应
  • 客户端发出JSP请求后,先进行转译,再进行编译成Servlet响应给浏览器
  • JSP以Java代码为主偏向于业务的处理,JSP以HTML标签为主,更多偏向于页面的显示

2. JSP语法

  • 声明区、程序代码区、表达式

    • 声明区:用于定义全局变量、方法、类

      <%! 
          int i;
      	public void setName(){… …} 
      %>
      
    • 程序代码区:定义局部变量和放入任意的Java代码

      <% 
      	int j; 
      	for (int k=0; k<10; k++) {
              … … 
          } 
      %>
      
    • 表达式:可以输出一个变量或一个具体内容,但=后面必须是字符串变量或者可以被转换成字符串的表达式

      不需要以;结束,只有一行

      <%=“hello world”%>
      <%=i+1%>
      
    • 案例:输出HTML表格

      id	name	age 	salary 
      1 	1 		1 		1
      2	2		2		2
      ... 
      5	5		5		5
      
      <%--
        Created by IntelliJ IDEA.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      
      
          实现表格的绘制
      
      
      
          <%
              for (int i = 1; i < 6; i++) {
          %>
          
          <%
              }
          %>
      
      id name age salary
      <%= i %> <%= i %> <%= i %> <%= i %>
  • 注释的示例

    <%--
      Created by IntelliJ IDEA.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        注释的测试
    
    
    
    <%-- 这是JSP文件中的注释方式,该方式浏览器是看不到的 --%>
    <%
        // Java语言中的单行注释   浏览器看不到哦
        /* Java语言中的多行注释   浏览器看不到哦! */
    %>
    
    
    
  • page几个常见的属性

    <%@ page import="java.util.List" %>
    <%@ page import="java.util.LinkedList" %>
    <%--
      Created by IntelliJ IDEA.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="utf-8" %>
    
    
        page指令的使用
    
    
    <%
        List list = new LinkedList();
    %>
    
    
    
  • JSP文件包含的方法

    • 静态包含

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <%-- 表示包含或引入head.jsp文件 include指令的方式  静态包含--%>
      <%@ include file="head.jsp"%>
      
      
          文件引入的使用
      
      
      
      
      
      
    • 动态包含(编译完,再包含,推荐使用)

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <%-- include动作的方式  动态包含 推荐 --%>
      
      
      
          文件引入的使用
      
      
      
      
      
      
  • JSP文件的转发

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        JSP页面的转发实现
    
    
    
        
    
    
    
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        转发的目标文件
    
    
    

    服务器转发后执行这里的代码哦!

    <%= "获取到的数值为:" + request.getParameter("name")%>

3. JSP内置对象

  • 常见的9种内置对象

    • 缓冲输出流对象out:

      直接调用方法,使用后关闭流

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      
      
          out内置对象的使用
      
      
      <%
          out.println("

      "); out.println("Hello World!"); out.println("

      "); //out.close(); int bufferSize = out.getBufferSize(); System.out.println("缓冲区的总大小是:" + bufferSize); int remaining = out.getRemaining(); System.out.println("缓冲区的剩余字节数为:" + remaining); System.out.println("已经使用的字节数为:" + (bufferSize - remaining)); out.clear(); // 清除缓冲区 数据不会输出 remaining = out.getRemaining(); System.out.println("缓冲区的剩余字节数为:" + remaining); %>
    • request(开发中常用):

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      
      
          request内置对象的使用
      
      
      <%
          String serverName = request.getServerName();
          System.out.println("获取到的服务器名称为:" + serverName);
          int serverPort = request.getServerPort();
          System.out.println("获取到的服务器端口号为:" + serverPort);
          // 通过内置对象设置属性信息,也就是存储数据
          request.setAttribute("name", "guanyu");
      %>
      <%-- 实现转发效果,也就是服务器跳转,两个JSP共享同一个request对象 --%>
      
      
      
      
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      
      
          获取request对象中的属性值
      
      
      <%= "获取到的属性值为:" + request.getAttribute("name")%>  <%--  guanyu --%>
      
      
      
    • response:打包给浏览器的响应信息

      <%@ page import="java.util.Date" %>
      <%@ page import="java.text.SimpleDateFormat" %>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      
      
          reponse内置对象的使用
      
      
      <%
          // 表示每隔1秒刷新一次
          response.addHeader("refresh", "1");
          // 获取当前系统时间
          Date d1 = new Date();
          SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
          String format = sdf.format(d1);
      %>
      <%= "当前时间为:" + format %>
      
      
      
    • session(开发中常用):

      只要浏览器不关闭,默认半个小时内都可以访问,且可以在任意JSP文件中获取数据

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      
      
          session内置对象的使用
      
      
      <%
          session.setAttribute("name", "liubei");
          System.out.println("session内置对象中的数据设置成功!");
      %>
      
      
      
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      
      
          获取session内置对象中的数据
      
      
      <%= "获取到的属性值为:" + session.getAttribute("name")%>
      
      
      
    • application:

      与session对象的区别:application多个浏览器之间可以共享对象,session只能在同一个浏览器中共享对象

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      
      
          application内置对象的使用
      
      
      <%
          application.setAttribute("name", "zhaoyun");
          System.out.println("application内置对象中的数据设置成功!");
      %>
      
      
      
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      
      
          application内置对象的获取
      
      
      <%= "获取到的application内置对象的属性为:" + application.getAttribute("name")%> <%-- zhaoyun --%>
      
      
      
    • pageContext:

      pageContext对象只在当前页面有效

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      
      
          pageContext内置对象的使用
      
      
      <%
          pageContext.setAttribute("name", "huangzhong");
          System.out.println("pageContext内置对象中的数据设置成功!");
      %>
      <%= "获取到的pageContext内置对象中的属性值为:" + pageContext.getAttribute("name")%>
      
      
      
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      
      
          pageContext内置对象属性的获取
      
      
      <%= "获取到的pageContext内置对象中的属性值为:" + pageContext.getAttribute("name")%> <%-- null --%>
      
      
      
    • exception

      (可选)可以在web.xml中添加error-page标签对所有的异常进行统一跳转到error.jsp处理

      使用配置文件后需要将isErrorPage属性注释

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <%@ page errorPage="error.jsp" %>
      
      
          exception内置对象的使用
      
      
      <%
          int ia = 10;
          int ib = 0;
          System.out.println(ia / ib); // 算术异常
      %>
      
      
      

      error.jsp中对带有errorPage跳转属性的JSP文件,要有对应的isErrorPage属性且值为true,若有全局配置文件则不需要写isErrorPage属性

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <%@ page isErrorPage="true" %>
      
      
          异常处理的页面
      
      
      <%
          if (exception != null) {
              out.println("异常的错误信息为:" + exception.getMessage());
          }
      %>
      
      
      

      全局配置后进行异常测试

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      
      
          发生另外一种异常的页面
      
      
      <%
          int[] arr = new int[5];
          System.out.println(arr[5]); // 数组下标越界异常
      %>
      
      
      

4. JavaBean组件

  • 使用场景:在JSP页面中实现对象的创建、属性的设置、属性的获取

  • JavaBean的组成要素

    属性:全部私有化,通过get和set方法进行访问

    方法:必须是public关键字修饰

    构造器 :必须有无参构造方法

  • JSP相关的IDEA快捷键:输入jsp后Tab,默认是带开始和结束标签;自闭和标签生成:开始标签的>前加/可以构成自闭和标签

  • 使用JSP语法规则:创建JavaBean、设置属性值、获取属性值

    public class Student {
        private int id;
        private String name;
    
        public Student() {
        }
    
        public Student(int id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        JavaBean组件的使用
    
    
    
    <%-- 表示创建Student类型的对象由student引用变量负责记录  有效范围是当前页面 --%>
    
    <%-- 表示将student对象中名字为id的属性值设置为1002 --%>
    
    
    
    <%
        // 创建Student类型的对象并设置成员变量的数值
        //Student student = new Student();
        //student.setId(1001);
        //student.setName("zhangfei");
    %>
    
    <%--<%= "获取到的学号是:" + student.getId() %>   <%– 1001 1002 –%>
    <%= "获取到的姓名是:" + student.getName() %> <%– zhangfei guanyu –%>--%>
    学号是:
    姓名是:
  • 使用JSP处理HTML中参数的传递(将参数使用JSP创建对象,使用JSP获取对象中的参数)

    
    
    
        
        实现向JavaBean组件传入参数的使用
    
    
    
    学号:
    姓名:
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        实现前端页面传入过来参数的接收和设置
    
    
    
    
    
    
    
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        实现JavaBean组件中对象属性值的打印
    
    
    
    <%-- 获取名字为student对象中属性为id的数值并打印 --%>
    经过参数赋值后获取到的学号是:
    经过参数赋值后获取到的姓名是:
  • 使用JSP实现对JavaBean对象的删除(在session.removeAttribute中删除)

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    
        实现JavaBean组件数据的删除
    
    
    <%
        // 表示从session对象中删除名字为student的属性
        session.removeAttribute("student");
    %>
    <%= "删除数据成功!" %>
    
    
    

5. MVC设计模式

  • MVC概述

    model:封装业务数据的JavaBean(Bean)、封装业务逻辑的JavaBean(Service)和访问数据库的DAO对象

    view:收集和展示数据,使用JSP

    controller:流程控制和页面跳转,使用Servlet

  • MVC示例:实现用户登录

    • 登录页面JSP的编写:

      注意字符集设置

      <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
      
      
      
        Login Page
      
      
      
      
      username:
      password:
    • DAO层实现步骤

      1. 编写数据库工具类

      2. 编写UserDao接口,其中有一个抽象方法User userLogin(User user)

      3. 编写UserDaoImpl类,重写User userLogin(User user)方法:通过传入的User对象获取参数信息进行查询,将查到的第一条内容打包成User对象返回,若查不到则返回null

      4. 编写UserDaoFactory类:包含一个静态方法UserDao getUser(),方法中直接返回new UserDaoImpl()

    • Service层实现步骤

      1. 编写UserService类:包含一个UserDao类型的成员变量userDao(合成复用原则)

        该类的带参构造方法空参构造方法中用UserDaoFactory类的方法去初始化成员变量userDao

        由于UserService中成员变量是UserDao,不希望在外部重新创建UserDao传入构造方法,所以这里构造方法改为无参的并且在其中用封装的工厂类来初始化成员变量

        该构造方法用于初始化成员变量userDao

        该类的成员方法User userLoginService(User user)中使用成员变量userDao调用User userLogin(User user)方法

        该方法用来获取经过查询后的用户User对象

      2. 编写UserServiceTest类:对UserService进行测试
        a. 创建UserDao接口类型的对象(接口引用指向实现类)

        b. 创建UserService类对象,传入刚才创建的UserDao对象

        c. 调用UserService类对象中的userLoginService方法传入指定uname和pw的User对象,最后打印返回值(User对象)

    • Servlet层实现步骤

      编写LoginServlet类:用于处理表单提交(urlPatterns内容同表单中action属性值)

      doGet中调用doPost,在doPost中进行处理的步骤:

      1. 获取表单中传入的请求参数
      2. 创建UserService对象,调用userLoginService方法获取查询结果
      3. 判断查询结果后打印到Server console中
    • View层实现步骤

      1. 登录成功:设置response调用重定向(客户端跳转用重定向)使页面跳转,选用request调用的session对User对象进行存储
      2. 登录成功:编写JSP跳转界面,使用session通过属性名获取属性的值
      3. 登陆失败:登录界面不变(服务器跳转用转发),request调用getRequestDispatcher获取转发器传入login页面,进行转发
      4. 登录失败:在Servlet应用类中添加请求参数;在login.jsp界面中,获取请求参数当参数为某个值将其显示否则不显示