详细解决方案
新职课(chapter5-2)
热度:38 发布时间:2023-12-20 12:58:08.0
文章目录
Servlet
API
生命周期
Request
Response
会话
初始化参数
注解
JSP
Servlet
Servlet(Server Applet)
作用:是?Java编写的服务器端程序,扩展基于HTTP协议的Web服务器
说成人话就是:运行于tomcat这样的应用服务器之上的处理web请求的类(接口),实现请求与处理的衔接
tomcat + Servlet
提供了JavaWeb的运行环境,类似Python中的UWSGI服务器,实现路由
工作流程
客户端发送请求?服务器
服务器启动并调?Servlet,Servlet根据客户端请求?成响应内容(调用我们自定义的逻辑)并将其传给服务器
服务器将响应返回客户端
API
Servlet是接口,需要实现;关系如图:
使用需要导入 javaee-api-7.0.jar,注意scope
继承和实现都可以
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
?法
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) ;
}
在单次请求中,可以存值取值@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
会话
request存的值只能在单次请求中保存,保存的数据不能跨??,当重定向时,request存的值会丢失
会话:从打开浏览器到关闭浏览器,期间访问服务器就称为?次会话
session的数据可以在多个??中共享protected void doGet ( HttpServletRequest req, HttpServletResponse resp) throws ServletException , IOException {
System . out. println ( "get---------" ) ; HttpSession session = req. getSession ( ) ; session. setAttribute ( "name" , "roy" ) ; session. getAttribute ( "name" ) ; String sid = session. getId ( ) ; System . out. println ( sid) ; 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" ) ) ; System . out. println ( config. getServletContext ( ) . getInitParameter ( "param_g" ) ) ; }
}
public class ServletParam extends HttpServlet {
@Override public void init ( ServletConfig config) throws ServletException {
System . out. println ( config. getInitParameter ( "param_l" ) ) ; System . out. println ( config. getServletContext ( ) . getInitParameter ( "param_g" ) ) ; }
}
注解
使用注解的方式实现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代码%> // 程序代码标签
看个例子,这里要用到 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
建立两个页面测试一下下面四个对象的作用域:
< % @ page contentType= "text/html;charset=UTF-8" language= "java" % >
< html> < head> < title> $Title $< / title> < / head> < body> < % request. setAttribute ( "a" , 10 ) ; % > request: < %= request. getAttribute ( "a" ) % > < % session. setAttribute ( "b" , 11 ) ; % > session: < %= session. getAttribute ( "b" ) % > < % application. setAttribute ( "c" , 12 ) ; % > appliaction: < %= application. getAttribute ( "c" ) % > < % pageContext. setAttribute ( "d" , 13 ) ; % > page: < %= pageContext. getAttribute ( "d" ) % > < / body>
< / html>
< % @ 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)
< % @ page contentType= "text/html;charset=UTF-8" language= "java" errorPage= "index2.jsp" % >
out: < % out. print ( 6 / 0 ) ; % >
< % @ page contentType= "text/html;charset=UTF-8" language= "java" isErrorPage= "true" % >
errorMSG: < %= exception. getMessage ( ) % >
指令
JSP指令?来设置整个JSP??相关的属性,有三个
可以包含多个page指令,<%@ page attribute="value" %>
include可以传入相对路径:<%@ include file="?件 url 地址" %>
将JSTL时会详细介绍标签库taglib
常见状态码
提升调错能力
EL表达式
之前使用小脚本的方式,把HTML代码和Java代码混着写,这样好吗?这样不好,容易傻
于是有了EL(expression language),用于展示数据 ,jsp中使用${ }
,包括的基础操作符:
来个例子看看,只能识别作用域中的变量,就是那几个内置对象 设置的变量才行< % @ 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??的编写
按功能分五部分:分别是 :核?标签 格式化标签 sql标签 xml标签 jstl函数
使用: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>
OK!