新职课(chapter5-2)

Servlet

  • Servlet(Server Applet)
  • 作用:是⽤Java编写的服务器端程序,扩展基于HTTP协议的Web服务器
    • 说成人话就是:运行于tomcat这样的应用服务器之上的处理web请求的类(接口),实现请求与处理的衔接
    • tomcat + Servlet 提供了JavaWeb的运行环境,类似Python中的UWSGI服务器,实现路由
  • 工作流程
    • 客户端发送请求⾄服务器
    • 服务器启动并调⽤Servlet,Servlet根据客户端请求⽣成响应内容(调用我们自定义的逻辑)并将其传给服务器
    • 服务器将响应返回客户端

API

  • Servlet是接口,需要实现;关系如图:
    1
  • 使用需要导入 javaee-api-7.0.jar,注意scope
    2
  • 继承和实现都可以
    // 业务逻辑类最终都是要通过这两个方方式调用的嘛
    public class ServletTest extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        	// 业务逻辑
            System.out.println("get---------");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        	// 业务逻辑
            System.out.println("post----------");
        }
    }
    
  • 如何验证,我们用到了实现的servlet,处理前端的请求?要用到WEB-INF/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>demo</servlet-name>
            <servlet-class>
                web.ServletTest
            </servlet-class>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>demo</servlet-name>
            <url-pattern>/test</url-pattern>
        </servlet-mapping>
    </web-app>
    
    • mapping中匹配到路径,就到servlet标签中找逻辑类,调用我们重写的 get/post 方法
    • flask用装饰器路由到处理方法,并限定请求方法;这里用xml映射和servlet类的请求方法包裹处理方法
    • 总之:都完成了路由和限定请求方法的作用

生命周期

  • 四个过程
    • 实例化 --先创建servlet实例
    • 初始化 --init()
    • 处理请求 --service(),即doGet/doPost方法(先调用父类的service())
    • 服务终⽌ --destory()
  • ⽤户发送第⼆次请求时,会判断servlet对象是否存在,但不再执⾏init(),直接执⾏ service ⽅法
    3

Request

  • HttpServletRequest 表示Http环境中的Servlet请求。它扩展于 javax.servlet.ServletRequest 接⼝
  • 更改一下业务逻辑,使用 req 获取参数 getParameter()
    public class ServletTest extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 业务逻辑
            System.out.println("get---------");
            String username = req.getParameter("username");
            String userage = req.getParameter("userage");
            System.out.println(username+"----"+userage);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 业务逻辑
            System.out.println("post----------");
            req.setCharacterEncoding("utf-8");
            String username = req.getParameter("username");
            System.out.println(username);
        }
    }
    
  • get请求不需要指定编码,post请求需要指定
  • 更改代码后需要重启tomcat应用服务器
  • 无论前端使用什么格式传递,后端都用 String 接收,也可以指定跳转到某个页面(redirect)
    @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 业务逻辑
        System.out.println("post----------");
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");
        System.out.println(username);
        String[] hobbyes = req.getParameterValues("hobby");
        for (String hobby : hobbyes) {
            System.out.println(hobby);
        }
        req.getRequestDispatcher("/index.html").forward(req,resp);  // 这个根目录就是web
    }
    
  • 在单次请求中,可以存值取值
    @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 业务逻辑
        System.out.println("get---------");
        String username = req.getParameter("username");
        String userage = req.getParameter("userage");
        System.out.println(username+"----"+userage);
    
        req.setAttribute("usersex", "man");
        Object sex = req.getAttribute("usersex");
        System.out.println(sex);
    
        req.getRequestDispatcher("/index.html").forward(req,resp);
    }
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>demo</title>
    </head>
    <body>
        <h1>this is demo for servlet</h1>
        <!-- 查询字符串  也叫路径参数-->
        <a href="test?username=roy&userage=18">servlet impl</a>
        <form action="test" method="post">
            username: <input type="text" name="username">
            <input type="submit" value="servlet">
            hobby: <input type="checkbox" value="basketball" name="hobby"> 篮球
            <input type="checkbox" value="volleyball" name="hobby"> 排球
            <input type="checkbox" value="soccer" name="hobby"> 足球
        </form>
    </body>
    </html>
    

Response

  • 目前能看到效果的就是redirect方法
    // req.getRequestDispatcher("/index.html").forward(req,resp);
    resp.sendRedirect("/index.html");
    
  • 转发和重定向的区别是什么呢?重定向第一次只返回页面的路径,会再次请求(地址栏修改了两次)
    4
    • 转发会直接返回路由路径

会话

  • request存的值只能在单次请求中保存,保存的数据不能跨⻚⾯,当重定向时,request存的值会丢失
  • 会话:从打开浏览器到关闭浏览器,期间访问服务器就称为⼀次会话
  • session的数据可以在多个⻚⾯中共享
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 业务逻辑
        System.out.println("get---------");
    
        // session
        HttpSession session = req.getSession();
        session.setAttribute("name", "roy");
        session.getAttribute("name");
        String sid = session.getId();
        System.out.println(sid);    // 520A40F0E0F2022B809BAC62D0579C5D
    
        resp.sendRedirect("/index.html");
    }
    

初始化参数

  • 分全局和局部初始化参数,编写两个业务类测试一下,对应的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-param>
            <param-name>param_g</param-name>
            <param-value>allen~</param-value>
        </context-param>
    
        <servlet>
            <servlet-name>demo</servlet-name>
            <servlet-class>
                web.ServletTest
            </servlet-class>
            <!--局部初始化参数-->
            <init-param>
                <param-name>param_l</param-name>
                <param-value>roy~</param-value>
            </init-param>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>demo</servlet-name>
            <url-pattern>/test</url-pattern>
        </servlet-mapping>
    
        <servlet>
            <servlet-name>demo2</servlet-name>
            <servlet-class>
                web.ServletParam
            </servlet-class>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>demo2</servlet-name>
            <url-pattern>/test2</url-pattern>
        </servlet-mapping>
    </web-app>
    
    public class ServletTest extends HttpServlet {
        @Override
        public void init(ServletConfig config) throws ServletException {
            System.out.println(config.getInitParameter("param_l")); // local param
            System.out.println(config.getServletContext().getInitParameter("param_g")); // global init param
        }
    }
    
    public class ServletParam extends HttpServlet {
        @Override
        public void init(ServletConfig config) throws ServletException {
            System.out.println(config.getInitParameter("param_l")); // local param
            System.out.println(config.getServletContext().getInitParameter("param_g")); // global init param
        }
    }
    

注解

  • 使用注解的方式实现Servlet,不使用xml文件映射;更像Python装饰器了
    @WebServlet(urlPatterns = {"/test/stu", "/test/student"}, name="stu", initParams = {
            @WebInitParam(name = "stu-param", value = "stu-value")
    }, loadOnStartup = 1)	// 值越小,优先级越高
    public class Student extends HttpServlet {
        @Override
        public void init(ServletConfig config) throws ServletException {
            System.out.println("stu servlet: " + config.getInitParameter("stu-param"));
        }
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("get");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            super.doPost(req, resp);
        }
    }
    

JSP

  • Java Server Pages,其根本是⼀个简化的Servlet设计,底层还是servlet
  • JSP就是在HTML⻚⾯中嵌⼊了java代码,得到 .jsp 动态页面(应以HTML为主)
    • 使用小脚本嵌入Java代码
    <%!变量或者⽅法声明%>	// 声明标签
    <%= 表达式%>			// 表达式标签
    <%java代码%>			// 程序代码标签
    
  • 看个例子,这里要用到 jasper-6.0.29.jar
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <body>
    	<%! int i=10;%>		<!--成员变量-->
    	<%! public void show(){}%> <!--成员⽅法-->
    	<%=i%> 	<!--输出变量值,要输出的话就不能跟分号-->
    </body>
    
  • 原理
    • 根据路径找到index.jsp⽂件
    • 翻译成index_jsp.java⽂件
    • 进⾏编译,产⽣⼀个index_jsp.class⽂件,加载运⾏
  • HTML代码最终以流的形式翻译输出到class,再写回浏览器(out.Writer()),这期间动态的换上了Java逻辑要输出的内容
    • 查看生成的 .java 文件会发现继承了HttpServlet

内置对象

  • 面试必考,有九个分别为:request、response、session、application、out、 pagecontext、config、page、exception
  • 建立两个页面测试一下下面四个对象的作用域:
    // index.jsp
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
      <head>
        <title>$Title$</title>
      </head>
      <body>
        <%  // 单次请求期间,通过index2.jsp访问就会变成null
            request.setAttribute("a",10); %>
        request: <%= request.getAttribute("a") %>
    
        <%  // 一次浏览器会话期间
            session.setAttribute("b", 11);
        %>
        session: <%= session.getAttribute("b")%>
    
        <%  // 整个程序运行期间,换了浏览器也行
            application.setAttribute("c", 12);
        %>
        appliaction: <%= application.getAttribute("c") %>
    
        <%  // 当前页面, page = java this 可以获取当前页面的java对象
            pageContext.setAttribute("d", 13);
        %>
        page: <%= pageContext.getAttribute("d") %>
      </body>
    </html>
    
    // index2.jsp
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>index2.jsp</title>
    </head>
    <body>
        request: <%= request.getAttribute("a") %>
    
        session: <%= session.getAttribute("b")%>
    
        application: <%= application.getAttribute("c") %>
    
        page: <%= pageContext.getAttribute("d") %>
    </body>
    </html>
    
    • 换了浏览器application的值仍然可以get到
  • 可以指定404页面(errorPage)
    // index.jsp
    <%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="index2.jsp" %>
    // 制造异常
    out: <% out.print(6/0);%>
    
    // index2.jsp
    <%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
    errorMSG: <%=exception.getMessage() %>
    

指令

  • JSP指令⽤来设置整个JSP⻚⾯相关的属性,有三个
    1
  • 可以包含多个page指令,<%@ page attribute="value" %>
    2
  • include可以传入相对路径:<%@ include file="⽂件 url 地址" %>
  • 将JSTL时会详细介绍标签库taglib

常见状态码

  • 提升调错能力
    3

EL表达式

  • 之前使用小脚本的方式,把HTML代码和Java代码混着写,这样好吗?这样不好,容易傻
  • 于是有了EL(expression language),用于展示数据,jsp中使用${ },包括的基础操作符:
    4
  • 来个例子看看,只能识别作用域中的变量,就是那几个内置对象设置的变量才行
    <%@ page import="java.util.List" %>
    <%@ page import="java.util.ArrayList" %>
    <%@ page import="java.util.Map" %>
    <%@ page import="java.util.HashMap" %><%--
      Created by IntelliJ IDEA.
      User: Windows10
      Date: 2021/12/28
      Time: 14:57
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
    <html>
    <head>
        <title>index2.jsp</title>
    </head>
    <body>
        <%
            request.setAttribute("p1", 15);
    
            List list = new ArrayList();
            list.add(18);
            pageContext.setAttribute("p2", list);
    
            Map map = new HashMap();
            map.put("m1", 66);
            application.setAttribute("p3", map);
        %>
        ${10+20}<br>
        p1: ${p1}<br>
        list: ${p2[0]}<br>
        map: ${p3.m1}
    </body>
    </html>
    
  • 如果内置对象设置的变量名冲突了呢?默认从小到大找:pageContext < request < session < application

JSTL

  • EL最初定义于JSTL1.0部分,JSP2.0之后将其搞出来成为了JSP的一部分
  • JSTL就是封装了EL的标签库,让我们更方便的使用EL,而定义的一些标签,更加简化jsp⻚⾯的编写
    • 比如EL取集合的值只能逐个写标签,不能循环取值
  • 按功能分五部分:分别是 :核⼼标签 格式化标签 sql标签 xml标签 jstl函数
    6
  • 使用:jakarta-taglibs-standard-1.1.2/lib/ 下的两个 jar ⽂件:standard.jar 和 jstl.jar ⽂件拷⻉到 /WEB-INF/lib/ 下
    • taglibs是JSTL的具体实现,所以下载的话还是taglibs,里面包含了jstl和standard,别搞混
  • 核⼼标签是最常⽤的 JSTL标签,看个例子
    <%@ page import="java.util.List" %>
    <%@ page import="java.util.ArrayList" %>
    <%@ page import="java.util.Date" %><%--
      Created by IntelliJ IDEA.
      User: Windows10
      Date: 2021/12/28
      Time: 21:12
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <h1>JSTL</h1>
        <c:set var="name" value="roy" scope="session"></c:set>
        ${name}
        <%--一般使用上面的EL表达式直接输出--%>
        <c:out value="${sessionScope.name}"></c:out>
    
        <%--分支    --%>
        <c:if test="${name=='roy'}">
            this is roy.
        </c:if>
    
        <%--多分支--%>
        <c:choose>
            <c:when test="${name=='allen'}">
                this is allen.
            </c:when>
            <c:otherwise>
                this is roy.
            </c:otherwise>
        </c:choose>
    
        <%
            List list = new ArrayList();
            list.add(18);
            list.add(20);
            pageContext.setAttribute("list", list);
        %>
        <%--循环结果--%>
        <c:forEach items="${list}" var="id" varStatus="stat">
            ${stat.count}---${stat.index}: ${id}<br>
        </c:forEach>
    
        <%--i18n--%>
        <%
            pageContext.setAttribute("time", new Date());
        %>
        <fmt:formatDate value="${time}" pattern="yyyy-MM-dd"></fmt:formatDate>
    </body>
    </html>
    
    • 比较常用的还有fmt:formatDate
  • OK!
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Roy_Allen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值