5.2、servlet获取参数【idea】
1、新建项目 - 新建
module
2、在
module
中添加web
3、创建
artifact
- 部署包4、
lib
和artifact
之间的关系
- 先有
artifact
,后来才添加的mysql.jar
,此时,这个jar
包并没有添加到部署包中。- 那么在
Project Structure
中有一个problems
提示,点击fix
,选择add to artifact
- 另外,可以直接把
lib
文件夹直接新建在WEB-INF
下。
- 缺点:这个
lib
只能是当前这个module
独享,如果有第二个module
,我们需要再次重复的新建lib
。5、在
deployment
,修改application Context
,然后在会带server
选项卡,检查URL的值。
URL
的值指的是,Tomact
启动完成后自动打开所指定的浏览器,其默认访问的网址。启动后,报
404
错误
404
:找不到指定的资源- 如果我们的网址是:http://localhost:8080/webPro1/,那么表明我们访问的是
index.html
可以通过
标签进行欢迎页。(在
tomcat
的web.xml
中设置,或者在自己项目的web.xml
中设置)<welcome-file-list> <welcome-file>index.htmlwelcome-file> <welcome-file>index.htmwelcome-file> <welcome-file>index.jspwelcome-file> welcome-file-list>
6、
405
问题:当前请求的方法不支持
- 如:我们表单
method=post
,那么Servlet
必须对应doPost
,否则报405
错误。7、空指针或者是
NumberFormatException
,因为有价格和库存,如果价格获取不到,结果你想对null
进行Integer.parseInt()
就会报错。错误的原因大部分是因为name = "price"
此处写错了,结果在Servlet
端还是使用request.getParameter("price")
去获取;
【add.html】
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<form action="add" method="post">
名称:<input type="text" name="fname"/>br>
单价:<input type="text" name="price"/>br>
库存:<input type="text" name="fcount"/>br>
备注:<input type="text" name="remark"/>br>
<input type="submit" value="添加"/>
form>
body>
html>
【addServlet.java】
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class addServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//post方式下,设置编码:防止中文乱码
request.setCharacterEncoding("UTF-8");
//1、获取用户(客户端)发送的数据
String fname = request.getParameter("fname");
String priceStr = request.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String fcountStr = request.getParameter("fcount");
Integer fcount = Integer.parseInt(fcountStr);
String remark = request.getParameter("remark");
//System.out.println("fname:"+fname);
FruitDAO fruitDAO = new FruitDAOImpl();
boolean flag = fruitDAO.addFruit(new Fruit(fname,price,fcount,remark));
System.out.println(flag == true ?"添加成功" : "添加失败");
}
}
【web.xml】
<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>AddServletservlet-name>
<servlet-class>com.javaweb.servlets.addServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>AddServletservlet-name>
<url-pattern>/addurl-pattern>
servlet-mapping>
web-app>
- 过程:
- 用户发请求,
action = post
- 项目中,
web.xml
中找到url-pattern = /add
->第12行 - 找第11行的
servlet-name = AddServlet
- 找和
servlet-mapping
中的servlet-name
一致的servlet
->第7行 - 找第8行中的
servlet-class
->com.javaweb.servlets.addServlet
- 用户发送的
post
请求(method = post
),因此tomcat
会执行AddServlet
中的doPost
方法
- 用户发请求,
post
方式下,设置编码为UTF-8
:防止中文乱码
request.setCharacterEncoding("UTF-8");
5.3.2、Get请求方式
1、get方式目前不需要设置编码(基于tomcat8)
2、如果是get请求发送的中文数据,转码稍微有点麻烦(tomcat之前)
String fname = request.getParameter("fanme");
//1.将字符串打散成字节数组
byte[] bytes = fname.getBytes("ISO-8859-1");
//2.将字节数组按照设定的编码方式重新组装成字符串
fname = new String(bytes, "UTF-8");
5.4、Servlet的继承关系——重点:查看服务方法(service()) 5.4.1、继承关系 5.4.2、相关方法注意:设置编码这一句代码必须在所有的获取参数动作之前
-
javax.servlet.Servlet
接口:void init(config)
:初始化方法void service(request, response)
:服务方法void destory()
:销毁方法
-
javax.servlet.GenericServlet
抽象类:void service(request, response)
:服务方法,仍然是抽象的
-
javax.servlet.http.HttpServlet
抽象子类:-
void service(request, response)
:服务方法,不是抽象的-
String method = req.getMethod();
获取请求的方式 -
各种if判断,根据请求方式不同,决定去调用不同的do方法
-
在HttpServlet`这个抽象类中,do方法都差不多
如:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_get_not_supported"); if (protocol.endsWith("1.1")) { resp.sendError(405, msg); } else { resp.sendError(400, msg); } }
-
service()
:- 当有请求过来时,
service
方法会自动响应(其实是tomcat
容器调用的) - 在
HttpServlet
中去分析请求的方式:get
、post
、head
、put
、delete
等 - 然后决定调用哪个
do
开头的方法 - 那么在
HttpServlet
中这些do
方法默认都是405的实现风格——要我们子类去实现对应的方法,否则默认会报405错误。
因此,在新建
Servlet
时,要去考虑请求方法,从而决定重写哪个do
方法。 -
-
生命周期:从出生到死亡的过程就是生命周期。
对应
Servlet
中的三个方法:init()
;service()
;destory()
;
-
默认情况下:
- 第一次接收请求时,这个
Servlet
会进行实例化(调用构造方法)、初始化(init()
),然后服务(service()
)。 - 从第二次请求开始,每一次都是服务
- 当容器关闭时,其中的所有
Servlet
实例会被销毁,调用destory()
;
- 第一次接收请求时,这个
-
通过案例发现:
-
Tomcat
只会创建一个Servlet
实例,所有的请求都是这个实例去响应。 -
默认情况下,第一次请求时,Tomcat才会去实例化,初始化,然后再服务。
- 优点:提高系统的启动速度
- 缺点:第一次请求时,耗时较长
-
因此得出结论:
- 如果需要提高系统的启动速度,当前默认情况就是这样。
- 如果需要提高响应速度,我们需要设置servlet的初始化时机。
-
-
Servlet的初始化时机:
-
默认第一次接收请求时,实例化,初始化
-
可以通过
来设置Servlet启动的先后顺序,数字越小,启动越靠前,最小为0。【web.xml】
<servlet> <servlet-name>Demo02Servletservlet-name> <servlet-class>com.javaweb.servlets.Demo02Servletservlet-class> <load-on-startup>1load-on-startup> servlet> <servlet-mapping> <servlet-name>Demo02Servletservlet-name> <url-pattern>/demo02url-pattern> servlet-mapping>
-
-
Servlet在容器中是:单例的、线程不安全的
-
单例:所有的请求都是一个实例去响应。
-
线程不安全:一个线程需要根据这个实例中的某个成员变量值去做逻辑判断,但是在中间某个时机,另一个线程改变了这个成员变量的值,从而导致第一个线程的执行路径发生变化。
线程1访问该代码块,获取了变量num的值为1,正准备将num=1送进判断之前,线程2访问该代码块,并将num值改变,此时线程1获取的num值也发生了改变,从而导致线程1的执行路径发生变化。
启发:尽量不要在Servlet中定义成员变量。如果不得不定义成员变量,那么不要去根据成员变量的值做一些逻辑判断。
-
1、HTTP
:Hyper Text Transfer
超文本传输协议。
2、HTTP
是无状态的。
3、HTTP
最大的作用就是确定了请求和响应数据的格式。
- 浏览器发送给服务器的数据:请求报文;
- 服务器返回给浏览器的数据:响应报文。
包含三个部分:
-
请求行
作用:展示当前请求的最基本信息
- 请求方式
- 请求的
URL
:访问地址 - 请求的
HTTP
协议的版本(一般是HTTP1.1
)
-
请求(消息)头
请求消息头中包含了很多客户端需要告诉服务器的信息。
作用:通过具体的参数对本次请求进行详细的说明
格式:键值对,键和值之间用冒号隔开
相对比较重要的请求消息头:
名称 功能 Host 服务器的主机地址 Accept 声明当前请求能够接受的媒体类型 Refer 当前请求来源页面的地址 Content-Length 请求体内容的长度 Content-Type 请求体的内容类型,这一项的具体值是媒体类型中的某一种 Cookie 浏览器访问服务器时携带的Cookie数据 -
请求体
作用:作为请求的主题,发送数据给服务器,具体来说其实就是
POST
请求方式下的请求参数。三种情况:
Get
方式:没有请求体,但是有一个queryString
Post
方式:有请求体,form data
Json
格式:有请求体,request payload
包含三个部分:
-
响应(状态)行
包含三个信息:
- 协议
- 响应状态码
- 响应状态
-
响应(消息)头
包含了服务器的信息;服务器发送给浏览器的信息(内容的媒体类型、编码、内容长度等)
-
响应体
响应的实际内容(比如添加
add.html
页面时,响应的内容就是…)
-
HTTP
是无状态的。HTTP
无状态:服务器无法判断请求是同一个客户端发过来的,还是不同的客户端发过来的。- 无状态带来的现实问题:第一次请求是添加商品到购物车,第二次请求是结账;如果这两次请求服务器无法区分是同一个用户的,那么就会导致混乱。
- 通过会话跟踪技术来解决无状态的问题
-
会话跟踪技术
- 客户端第一次发请求给服务器,服务器获取
session
,获取不到,则创建新的session
,然后响应给客户端。 - 下次客户端给服务器发请求时,会把
sessionID
带给服务器,那么服务器就能获取到了,服务器判断这一次请求和上次某次请求是同一个客户端,从而能够区分开客户端。 - 常用的API:
request.getSession()
:获取当前的会话,没有则创建一个新的会话request.getSession(true)
:效果和不带参数相同request.getSession(false)
:获取当前会话,没有则返回null
,不会创建新的session.getId()
:获取sessionID
session.isNew()
:判断当前的session
是否是新的session.getMaxInactiveInterval()
:获取session的非激活间隔时长,默认1800秒。session.setMaxInactiveInterval()
:获取session的非激活间隔时长session.invalidate()
:强制性让会话立即失效- …
- 客户端第一次发请求给服务器,服务器获取
-
session保存作用域
- session保存作用域是和具体的某一个session对应的
- 常用的API:
void session.setAttribute(key,value)
Object session.getAttribute(key)
void removeAttribute(key)
-
服务器内部转发:
request.getRequestDispatcher("...").forward(request,response);
- 一次请求响应的过程,对于客户端而言,内部经过了多少次转发,客户端是不知道的。
- 地址栏无变化
-
客户端重定向:
response.sendRedirect("...");
- 两次请求响应的过程。客户端肯定知道请求
URL
有变化。 - 地址栏有变化
- 两次请求响应的过程。客户端肯定知道请求
-
Thymeleaf优势
- SpringBoot官方推荐使用的试图模板技术,和SpringBoot完美整合。
- 不经过服务器运算仍然可以直接查看原始值,对前端工程师更友好。
-
流程:
-
添加
thymeleaf
的jar
包 -
在
web.xml
文件中添加配置【web.xml】
<context-param> <param-name>view-prefixparam-name> <param-value>/param-value> context-param> <context-param> <param-name>view-suffixparam-name> <param-value>.htmlparam-value> context-param>
- 配置前缀:
view-prefix
- 配置后缀:
view-suffix
- 配置前缀:
-
新建一个
servlet
类ViewBaseServlet
【ViewBaseServlet.java】
package com.fruit.myssm.myspingmvc; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.WebContext; import org.thymeleaf.templatemode.TemplateMode; import org.thymeleaf.templateresolver.ServletContextTemplateResolver; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class ViewBaseServlet extends HttpServlet { private TemplateEngine templateEngine; @Override public void init() throws ServletException { // 1.获取ServletContext对象 ServletContext servletContext = this.getServletContext(); // 2.创建Thymeleaf解析器对象 ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext); // 3.给解析器对象设置参数 // ①HTML是默认模式,明确设置是为了代码更容易理解 templateResolver.setTemplateMode(TemplateMode.HTML); // ②设置前缀 String viewPrefix = servletContext.getInitParameter("view-prefix"); templateResolver.setPrefix(viewPrefix); // ③设置后缀 String viewSuffix = servletContext.getInitParameter("view-suffix"); templateResolver.setSuffix(viewSuffix); // ④设置缓存过期时间(毫秒) templateResolver.setCacheTTLMs(60000L); // ⑤设置是否缓存 templateResolver.setCacheable(true); // ⑥设置服务器端编码方式 templateResolver.setCharacterEncoding("utf-8"); // 4.创建模板引擎对象 templateEngine = new TemplateEngine(); // 5.给模板引擎对象设置模板解析器 templateEngine.setTemplateResolver(templateResolver); } protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException { // 1.设置响应体内容类型和字符集 resp.setContentType("text/html;charset=UTF-8"); // 2.创建WebContext对象 WebContext webContext = new WebContext(req, resp, getServletContext()); // 3.处理模板数据 templateEngine.process(templateName, webContext, resp.getWriter()); } }
4.使自己新建的servlet
继承ViewBaseServlet
import com.fruit.dao.FruitDAO;
import com.fruit.dao.impl.FruitDAOImpl;
import com.fruit.myssm.myspingmvc.ViewBaseServlet;
import com.fruit.pojo.Fruit;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
//servlet从3.0版本开始支持注解方式的注册
@WebServlet("/index")
public class indexServlet extends ViewBaseServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
FruitDAO fruitDAO = new FruitDAOImpl();
List<Fruit> fruitList = fruitDAO.getFruitList();
//保存到session作用域
HttpSession session = request.getSession();
session.setAttribute("fruitList", fruitList);
//此处的视图名称是 index
//那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图名称 上去
//逻辑视图名称:index
//物理视图名称:view-prefix + 逻辑视图名称 + view-suffix
//所以真实的视图名称:/index.html
super.processTemplate("index",request,response);
}
}
5.根据逻辑视图名称,得到物理视图名称
- 视图名称是
index
- 那么
thymeleaf
会将这个 逻辑视图名称 对应到 物理视图名称 上去 - 逻辑视图名称:
index
- 物理视图名称:
view-prefix
+ 逻辑视图名称 +view-suffix
- 所以真实的视图名称:
/index.html
-
原始情况下,保存作用域有四个:
page
:页面级别,现在几乎不用request
:请求级别,一次请求响应范围session
:会话级别,一次会话范围application
:应用级别,整个应用程序范围
-
request
:一次请求响应范围-
重定向
-
内部转发
-
代码演示:
【demo01.java】
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/demo01")
public class Demo01Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.向request保存作用域保存数据
request.setAttribute("uname","lili");
//2.重定向
//response.sendRedirect("demo02");
//3.服务器端转发
request.getRequestDispatcher("demo02").forward(request,response);
}
}
【demo02.java】
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/demo02")
public class Demo02Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取request保存作用域保存的数据
Object obj = request.getAttribute("uname");
System.out.println("unameObj = " + obj);
}
}
-
session
:一次会话范围有效,同一个客户端有效
此时,第二个客户端请求,服务器端无法打印出
lili
。 -
application
:一次应用程序范围有效
【demo5.java】
//演示application保存作用域 @WebServlet("/demo05") public class Demo05Servlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.向application保存作用域保存数据 //ServletContext:Servlet上下文 ServletContext application = request.getServletContext(); application.setAttribute("uname","lili"); //2.重定向 //response.sendRedirect("demo02"); //3.服务器端转发 request.getRequestDispatcher("demo02").forward(request,response); } }
【demo06.java】
@WebServlet("/demo06") public class Demo06Servlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.获取application保存作用域保存的数据 ServletContext application = request.getServletContext(); Object obj = application.getAttribute("uname"); System.out.println("unameObj = " + obj); } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)