当前位置: 代码迷 >> 综合 >> 新职课(chapter5-2)
  详细解决方案

新职课(chapter5-2)

热度:38   发布时间:2023-12-20 12:58:08.0

文章目录

  • Servlet
    • API
    • 生命周期
    • Request
    • Response
    • 会话
    • 初始化参数
    • 注解
  • JSP
    • 内置对象
    • 指令
    • 常见状态码
    • EL表达式
    • JSTL

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 {
          @Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          // 业务逻辑System.out.println("get---------");}@Overrideprotected 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 {
          @Overrideprotected 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);}@Overrideprotected 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)
    @Overrideprotected 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
    }
    
  • 在单次请求中,可以存值取值
    @Overrideprotected 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---------");// sessionHttpSession session = req.getSession();session.setAttribute("name", "roy");session.getAttribute("name");String sid = session.getId();System.out.println(sid);    // 520A40F0E0F2022B809BAC62D0579C5Dresp.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 {
          @Overridepublic void init(ServletConfig config) throws ServletException {
          System.out.println(config.getInitParameter("param_l")); // local paramSystem.out.println(config.getServletContext().getInitParameter("param_g")); // global init param}
    }
    
    public class ServletParam extends HttpServlet {
          @Overridepublic void init(ServletConfig config) throws ServletException {
          System.out.println(config.getInitParameter("param_l")); // local paramSystem.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 {
          @Overridepublic void init(ServletConfig config) throws ServletException {
          System.out.println("stu servlet: " + config.getInitParameter("stu-param"));}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          System.out.println("get");}@Overrideprotected 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访问就会变成nullrequest.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: Windows10Date: 2021/12/28Time: 14:57To 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: Windows10Date: 2021/12/28Time: 21:12To 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!