目录
1、概述
狭义的Servlet是指Java语⾔实现的⼀个接⼝,⼴义的Servlet是指任何实现了这个Servlet接⼝的类,⼀般情况下,⼈们将Servlet理解为后者。
作用:用于处理前端发送的请求
这里分享一篇文章,作者写得很好,学完Servlet再回头看,会有更深的理解。
https://www.zhihu.com/question/21416727/answer/690289895
2、源码结构
3、自己写一个Servlet
1.首先要引入jar包,因为我创建的项目是JAVAEE项目,自带Maven和ServletApi的jar包
没有的话要自己手动引入
2.右击新建一个类 MyServlet 继承 HttpServlet
右击-生成-重写方法,选择doget,dopost
package com.example.JavawebProject1;
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;
/**
* @author suyiping
* @creator 2021-08-03 0:09
*/
@WebServlet("/myservlet")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("hello");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
3.在webapps下,新建一个index.jsp文件
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>JSP - Hello World</title>
</head>
<body>
<h1><%= "Hello World!" %>
</h1>
<br/>
<a href="hello-servlet">Hello Servlet</a>
<br>
<a href="myservlet">myservlet</a>
</body>
</html>
4.启动服务器。点击myservlet
这时候就会执行myservlet的doget方法了
5.如果想执行dopost方法,前端要用表单提交
<form action="myservlet" method="post">
password:<input type="password" name="password">
<br>
sex: <input type="text" name="sex">
<br>
爱好:<input type="checkbox" name="hobby" value="basketball">篮球
<input type="checkbox" name="hobby" value="vollyball">排球
<input type="checkbox" name="hobby" value="football">足球
<button type="submit">提交</button>
</form>
4、Servlet工作原理
获取HttpServletRequest请求对象,处理数据之后,使用HttpServletResponse响应对象,响应传来的值.
通过request.getServletContext();获取context,进行全局数据的存取
5、Servlet生命周期
浏览器第一次请求Servlet,Servlet会先执行构造方法,再执行init方法,这两个方法只会执行一遍,因为Servlet是单例的,创建完之后就会放在那里。然后才会执行service方法(service会判断是doGet或者doPost或者其他,再进行相应方法的执行)。之后每从浏览器请求一次,就会执行一次service方法,构造方法和init方法不会再执行。
关闭服务器的时候,才会执行destroy方法进行销毁。
6、请求
常用方法:
1)String getParameter(String name) 根据表单组件名称获取提交数据,返回值是String
注:服务器在接收数据时使⽤字符串统⼀接收
2)String[ ] getParameterValues(String name) 获取表单组件对应多个值时的请求数据
3)void setCharacterEncoding(String charset) 指定每个请求的编码(针对post请求才起作⽤)
4)RequestDispatcher getRequestDispatcher(String path) --跳转⻚⾯
返回⼀个RequestDispatcher对象,该对象的forward( )⽅法⽤于转发请求
request.getRequestDispatcher("/success.jsp").forward(request,response)
5)存值 request.setAttribute("key",value);
6)取值 request.getAttribute("key");//取值后需要向下转型
示例: String a1=(String)request.getAttribute("uname");
示例:
1.获取单个参数:req.getParameter("parm");
无论前端传什么数据过来,后端都是用String接收
get请求:通过超链接,或者在浏览器地址栏直接输入,就可以请求
请求的格式如下:
http://localhost/JavawebProject1/myservlet?username=哈哈&age=19
在servlet中通过request获取参数,get请求在tomcat8之后,不用手动处理中文乱码。
请求格式: key=value&key2=value2
多个参数用&隔开
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("hello");
String username = req.getParameter("username");
String age = req.getParameter("age");
System.out.println(username+age);
}
post请求:通过method为post的表单请求
<form action="myservlet" method="post">
password:<input type="password" name="password">
<br>
sex: <input type="text" name="sex">
<button type="submit">提交</button>
</form>
点击提交,就会传入Servlet中的doPost方法
doPost方法要手动设置编码格式,不然中文会乱码
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
String password = req.getParameter("password");
String sex = req.getParameter("sex");
System.out.println(password+sex);
}
2.获取参数数组 String[] strs=req.getParameterValues("param");
例如在传递多选框的值的时候就可以使用
<form action="myservlet" method="post">
password:<input type="password" name="password">
<br>
sex: <input type="text" name="sex">
<br>
爱好:<input type="checkbox" name="hobby" value="basketball">篮球
<input type="checkbox" name="hobby" value="vollyball">排球
<input type="checkbox" name="hobby" value="football">足球
<button type="submit">提交</button>
</form>
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
String password = req.getParameter("password");
String sex = req.getParameter("sex");
System.out.println(password+sex);
String[] hobbies = req.getParameterValues("hobby");
for(String hobby : hobbies){
System.out.println(hobby);
}
}
3.跳转页面req.getRequestDispatcher("/hello.html").forward(req,resp);
//使用forward方法,hello前面的斜杆必须要,代表从webapp目录下开始找
req.getRequestDispatcher("/hello.html").forward(req,resp);
4.后端给前端jsp存值request.setAttribute("key",value);
后端代码:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
String password = req.getParameter("password");
String sex = req.getParameter("sex");
System.out.println(password+sex);
String[] hobbies = req.getParameterValues("hobby");
if(hobbies != null){
for(String hobby : hobbies){
System.out.println(hobby);
}
}
//存的值的生命周期是单次请求,下次请求,上一次存的值就没了。
req.setAttribute("password",password);
req.setAttribute("hobby",hobbies);
//跳转页面
req.getRequestDispatcher("/myjsp.jsp").forward(req,resp);
}
前端代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>这是从后台传来的password:${password}</h1>
</body>
</html>
后端给后端另一个Servlet传值,也可以用上面那个方法,并使用forward跳转请求
取值的话,用req.getAttribute("attr");需要进行类型转换
(String) req.getAttribute("password");
补充1:客户端如何发送数据给服务器
⽅式1:通过表单 get/post提交
⽅式2:通过a标签发送数据(get提交)
<a href="请求名?key=value&key=value&key=value...">
示例:
<a href="/login?a=10&name=abc&pass=123">
这⾥的key值=表单元素的控件名,value值=表单中控件的value属性值
注:第⼀个参数使⽤?拼接,之后的参数使⽤&拼接,获取数据还是通过
String name=request.getParameter("name");获取
⽅式3:通过地址栏直接拼接-get请求
⽅式4:js提交数据-get请求
location.href="⽬标请求?key=value&key=value"
注:⽅式2/3都属于get提交⽅式,表单提交可以使⽤get、post提交⽅式
补充2:处理请求乱码的问题
⽅式1:request.setCharacterEncoding("UTF-8");//获取post提交过来的数据管⽤
⽅式2: String s=new String(变量名.getBytes("ISO-8859-1"),"UTF-8");//针对于get提交时中⽂乱码.tomcat8后不需要
示例: String s=new String(request.getParameter("key").getBytes("ISO-8859-1"),"UTF-8");
⽅式3:修改tomcat中配置⽂件://使⽤于get提交
在Tomcat⽬录结构\conf\server.xml中设置字符集
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" />
注意:tomcat8.0以后不需要⼿动设置
补充3:get和post的区别
1、GET请求:请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数⽤&连接。URL的编码格式采⽤的是ASCII编码,⽽不是uniclde,即是说所有的⾮ASCII字符都要编码之后再传输。
POST请求:POST请求会把请求的数据放置在HTTP请求包的包体中。上⾯的item=bandsaw就是实际的传输数据。
因此,GET请求的数据会暴露在地址栏中,⽽POST请求则不会。
2、传输数据的⼤⼩
在HTTP规范中,没有对URL的⻓度和传输的数据⼤⼩进⾏限制。但是在实际开发过程中,对于GET,特定的浏览器和服务器对URL的⻓度有限制。因此,在使⽤GET请求时,传输数据会受到URL⻓度的限制。
对于POST,由于不是URL传值,理论上是不会受限制的,但是实际上各个服务器会规定对POST提交数据⼤⼩进⾏限制,Apache、IIS都有各⾃的配置。
3、安全性
POST的安全性⽐GET的⾼。这⾥的安全是指真正的安全,⽽不同于上⾯GET提到的安全⽅法中的安全,上⾯提到的安全仅仅是不修改服务器的数据。⽐如,在进⾏登录操作,通过GET请求,⽤户名和密码都会暴露再URL上,因为登录⻚⾯有可能被浏览器缓存以及其他⼈查看浏览器的历史记录的原因,此时的⽤户名和密码就很容易被他⼈拿到了。除此之外,GET请求提交的数据还可能会造成Cross-site request frogery攻击
7、响应
常用方法:
1.重定向跳转
resp.sendRedirect("myjsp.jsp");
与forward的不同:
https://blog.csdn.net/molkor/article/details/119742478
2.设置响应类型、字符编码
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
3.设置Cookie
resp.addCookie(new Cookie("username","yiping"));
4.获取响应字符流,可以将要返回的内容通过字符流返回给前端
resp.getWriter().println("123");
resp.getWriter().write("456");
response.getWriter().print(),不仅可以打印输出文本格式的(包括html标签),还可以将一个对象以默认的编码方式转换为二进制字节输出
response.getWriter().writer(),只能打印输出文本格式的(包括html标签),不可以打印对象。
//输出对象
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Person person = new Person();
person.setName("sjl");
response.getWrier().print(person);
}
运行结果 :
server.Person@5bd5ab
如果使用response.getWriter().writer(),则代码会报错
响应字符流可以用于页面跳转
resp.getWriter().print("<script type='text/javascript'>alert('登录失败');location='../login.jsp'</script>");
8、Session
request存的值只能在单次请求中保存,保存的数据不能跨⻚⾯,当重定向时,request存的值会丢失
session的数据可以在多个⻚⾯中共享,即使重定向⻚⾯,数据不会丢失
session中可以包含n个request。
会话的概念:从打开浏览器到关闭浏览器,期间访问服务器就称为⼀次会话
常用方法:
void setAttribute(String key,Object value) 以key/value的形式保存对象值,将数据存储在服务器端
Object getAttribute(String key) 通过key获取对象值
void invalidate() 设置session对象失效
String getId() 获取sessionid,当第⼀次登录成功后,session会产⽣⼀个
唯⼀的id,浏览器之后访问时如果发现id值还是之前id,那么说明 当前访问的属于同⼀个会话
void setMaxInactiveInterval(int interval) 设定session的⾮活动时间
示例:
⽅式1: session.setMaxInactiveInterval(10*60);//设置有效时间为10分钟
⽅式2:修改web.xml
<session-config>
<session-timeout>10</session-timeout>//单位:分钟
</session-config>
int getMaxInactiveInterval() 获取session的有效⾮活动时间(以秒为单位),默认的有效时间:30分钟
void removeAttribute(String key)
从session中删除指定名称(key)所对应的对象
⼩结 :让session失效的⽅式
(1)invalidate() (2)removeAttribute("key") (3)直接关闭浏览器。
9、初始化参数
①局部初始化参数,在servlet注解里添加,或者在web.xml配置里添加
@WebServlet(name = "helloServlet", value = "/hello-servlet",
initParams = {
@WebInitParam(name = "name", value = "小明"),
@WebInitParam(name = "pwd", value = "123456")
}
)
public class HelloServlet extends HttpServlet {
...
}
②全局初始化参数,在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">
<context-param>
<param-name>appname</param-name>
<param-value>yiping's app</param-value>
</context-param>
</web-app>
使用方式
局部初始化参数,存放在Servlet中的ServletConfig config属性
全局初始化参数,通过servletContext.getInitParameter("appname")获取
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html;charset=UTF-8");
//initParam
ServletConfig servletConfig = this.getServletConfig();
//获取局部初始化参数
Enumeration<String> paramNames = servletConfig.getInitParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = paramNames.nextElement();
out.println(paramName + ":" + servletConfig.getInitParameter(paramName) + "<br>");
}
//获取全局初始化参数
out.println("全局初始化参数:appname="+this.getServletContext().getInitParameter("appname")+ "<br>");
out.println("全局初始化参数:appname="+servletContext.getInitParameter("appname")+ "<br>");
}
10、Servlet注解
属性 | 类型 | 是否必须 | 说明 |
urlPatterns/value | String[] | 否 | 这两个属性作用相同,指定Servlet处理的url |
name | String | 否 | 指定Servlet名称 |
loadOnStartup | int | 否 | 标记容器是否在应用启动时就加载这个Servlet,并设置优先级,数字越低越优先 |
initParams | WebInitParam[] | 否 | 配置初始化参数 |
displayName | String | 否 | 指定Servlet显示名称 |
asyncSupported | boolean | 否 | 指定Servlet是否支持异步操作模式 |
示例:
@WebServlet(name = "login",
urlPatterns = "/login",
loadOnStartup = 1,
initParams = {
@WebInitParam(name="name", value="yiping"),
@WebInitParam(name="encoding", value="utf-8")
}
)
public class UserServlet extends HttpServlet {
}
(1).loadOnStartup属性:标记容器是否在启动应用时就加载Servlet,默认不配置或数值为负数时表示客户端第一次请求Servlet时再加载;0或正数表示启动应用就加载,正数情况下,数值越小,加载该Servlet的优先级越高;
(2). name属性:可以指定也可以不指定,通过getServletName()可以获取到,若不指定,则为Servlet的完整类名,如:cn.edu.njit.servlet.UserServlet
(3).urlPatterns/value属性: String[]类型,可以配置多个映射,如:urlPatterns={"/user/test", "/user/example"}
(4).在使用注解方式时,需要注意:
<web-app> </web-app>根元素中不能配置属性metadata-complete="true",否则无法加载Servlet。metadata-complete属性表示通知Web容器是否寻找注解,默认不写或者设置false,容器会扫描注解和Web分片,为Web应用程序构建有效的元数据;设置true,表示将由部署描述符为Web程序提供所有的配置信息,web.xml中不能再配置该Servlet
(5).urlPatterns的常用规则:
/*或者/:拦截所有
*.do:拦截指定后缀
/user/test:拦截路径
/user/*.do、/*.do、test*.do都是非法的,启动时候会报错
示例:
映射的URL |
/hello |
/bbs/admin/* |
/bbs/* |
*.jsp |
/ |