共计 14372 个字符,预计需要花费 36 分钟才能阅读完成。
Servlet
Servlet 是 sun 公司开发的解决动静 web 的技术
Servlet 有两个默认的实现类:HttpServlet、GenericServlet
开发 Servlet 程序的步骤:
- 编写一个类,实现 Servlet 接口
- 把开发好的 Java 类部署到 web 服务器中
实现了 Servlet 接口的 java 程序称为 Servlet
创立 HelloServlet 我的项目
- 构建一个一般的 maven 我的项目,删除 src 文件夹,这个空的工程作为 maven 主工程
-
引入 servlet jsp 依赖到 pom.xml
<dependencies> <!-- 增加 Servlet 和 JSP 依赖 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> </dependency> </dependencies>
或手动下载 jar 包到文件夹中
依赖下载地址:https://mvnrepository.com/
- 新建 Module 子模块 servlet01(maven-archetype-webapp)
父我的项目中的 java 子项目能够间接应用,反之不能够
问题 1: 子项目 pom 中没有 parent 标签
解决:在子项目的 pom.xml 中手动增加 parent 标签并刷新 maven
-
<parent> <groupId>cn.itxiaoma</groupId> <artifactId>HelloMaven</artifactId> <version>1.0-SNAPSHOT</version> </parent>
问题 2:子项目 pom 文件有一条横线并变灰
解决:file –>setting–>maven–>Ignored Files 将清单中对应我的项目的 pom.xml 文件勾销选中
-
将 servlet01 中的 web.xml 改为最新,在 main 目录下新建 java 和 resources
<?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"metadata-complete="true"> </web-app>
- 在 java 目录下新建 package 包 cn..itxiaoma.servlet
-
在包下新建 java 类 HelloServlet,并实现 Servlet 接口(继承 HttpServlet)
package cn.itxiaoma.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; public class HelloServlet extends HttpServlet { //get 和 post 只是申请实现的不同形式,业务逻辑一样,因而能够相互调用 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {PrintWriter printWriter = resp.getWriter(); printWriter.print("Hello Servlet"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp); } }
-
编写 Servlet 的映射
浏览器连贯的是 web 服务,因而须要在 web 服务中注册咱们写的 Servlet,并配置浏览器可能拜访的门路
<!-- 注册 Servlet--> <servlet> <servlet-name>hello</servlet-name> <servlet-class>cn.itxiaoma.servlet.HelloServlet</servlet-class> </servlet> <!-- Servlet 的申请门路 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
-
配置 Tomcat
Run > Edit Configurations > + > Tomcat Server – Local > Application server: 抉择 Tomcat 目录
Deployment > + > servlet01:war exploed
Application Context: /servlet01_war_exploded
-
启动测试
http://localhost:8081/servlet…
Servlet 原理
- 浏览器发送 http 申请 (service) 到 web 容器(Tomcat)
- 首次拜访的申请会加载 Servlet 类到内存
- web 容器生成申请 (Request) 和响应 (Response) 两个对象,并调用 Servlet 的 service 办法
- Request 会从 service 拿到申请,并执行咱们重写的解决办法,失去响应信息传给 Response
-
web 容器读取响应信息传回浏览器
Servlet Mapping 问题
指定映射门路
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
多映射门路
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping>
默认申请门路(会笼罩首页)
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
指定后缀 / 前缀
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>*.test</url-pattern> </servlet-mapping>
注:自定义后缀 / 前缀 * 前不能有映射门路
自定义异样解决 ErrorServlet
cn/itxiaoma/servlet/ErrorServlet.java
package cn.itxiaoma.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; public class ErrorServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8"); PrintWriter pw = resp.getWriter(); pw.print("<h1>404</h1>"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp); } }
src/main/webapp/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"metadata-complete="true"> <servlet> <servlet-name>hello</servlet-name> <servlet-class>cn.itxiaoma.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <servlet> <servlet-name>error</servlet-name> <servlet-class>cn.itxiaoma.servlet.ErrorServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>error</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
优先级问题:制订了固有的映射门路优先级最高,找不到再走默认的映射
ServletContext 对象
web 容器在启动的时候,它会为每个 web 程序创立一个 ServletContext 对象,代表以后的 web 利用
1. 共享数据
在一个 Servlet 中保留的数据,能够在其余 Servlet 中获取
web.xml
<servlet> <servlet-name>get</servlet-name> <servlet-class>cn.itxiaoma.servlet.GetServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>get</servlet-name> <url-pattern>/get</url-pattern> </servlet-mapping>
HelloServlet.java
package cn.itxiaoma.servlet; 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 HelloServlet extends HttpServlet { //get 和 post 只是申请实现的不同形式,业务逻辑一样,因而能够相互调用 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletContext context= this.getServletContext(); String username = "Apple"; context.setAttribute("username", username); System.out.println(username); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp); } }
GetServlet.java
package cn.itxiaoma.servlet; 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; import java.io.PrintWriter; public class GetServlet extends HttpServlet { //get 和 post 只是申请实现的不同形式,业务逻辑一样,因而能够相互调用 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletContext context = this.getServletContext(); PrintWriter printWriter = resp.getWriter(); resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8"); printWriter.print("Username:" + context.getAttribute("username")); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp); } }
2. 获取初始化参数
web.xml
<context-param> <param-name>url</param-name> <param-value>jdbc:mysql://localhost:3306/testdb</param-value> </context-param>
HelloServlet.java
package cn.itxiaoma.servlet; 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; import java.io.PrintWriter; public class HelloServlet extends HttpServlet { //get 和 post 只是申请实现的不同形式,业务逻辑一样,因而能够相互调用 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletContext context= this.getServletContext(); String url = context.getInitParameter("url"); resp.getWriter().print(url); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp); } }
3. 申请转发
ServletContext context= this.getServletContext(); RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");// 转发的申请门路 requestDispatcher.forward(req, resp);
4. 读取资源文件
resources 文件夹下新建 db.properties(会打包到 classes 门路下,称为 classpath)
username=root password=123456
读取资源文件
ServletContext context= this.getServletContext(); InputStream inputStream = context.getResourceAsStream("/WEB-INF/classes/db.properties"); Properties properties = new Properties(); properties.load(inputStream); String username = properties.getProperty("username"); String password = properties.getProperty("password"); resp.getWriter().print(username + password);
HttpServletResponse
web 服务器接管到客户端的 http 申请,针对这个申请,分表创立一个代表申请的 HttpServletRequest 对象,和一个代表响应的 HttpServletResponse 对象
javax/servlet/ServletResponse.java
负责向浏览器发送数据的办法
public ServletOutputStream getOutputStream() throws IOException; public PrintWriter getWriter() throws IOException;
负责向浏览器发送响应头的办法
public void setCharacterEncoding(String charset); public void setContentLength(int len); public void setContentLengthLong(long len); public void setContentType(String type);
常见利用
- 向浏览器输入音讯
-
下载文件
- 获取下载文件门路,文件名
- 获取下载文件的输出流
- 创立缓冲区
- 获取 OutputStream 对象
- 将 FileOutputStream 流写入 Buffer 缓冲区
- 应用 OutputStream 将缓冲区中的数据输入到客户端
String realPath = "/Users/4wheels/Downloads/test.jpg"; String filename = realPath.substring(realPath.lastIndexOf("/") + 1); resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); // 获取文件输出流 FileInputStream inputStream = new FileInputStream(realPath); // 缓冲区 int len = 0; byte[] buffer = new byte[1024]; ServletOutputStream servletOutputStream = resp.getOutputStream(); while ((len = inputStream.read(buffer)) > 0) {servletOutputStream.write(buffer, 0, len); } inputStream.close(); servletOutputStream.close();
-
验证码性能
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 浏览器 3 秒主动刷新 resp.setHeader("refresh", "3"); // 在内存中创立图片 BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB); // 绘制图片 Graphics2D g = (Graphics2D) image.getGraphics(); g.setColor(Color.white); g.fillRect(0, 0, 80, 20);// 绘制填色矩形 g.setColor(Color.BLACK); g.setFont(new Font(null, Font.BOLD, 20)); g.drawString(makeNum(), 2, 20); resp.setContentType("image/jpeg"); resp.setDateHeader("expires", -1);// 浏览器不缓存 resp.setHeader("Cache-COntrol", "no-cache"); resp.setHeader("Pragma", "no-cache"); ImageIO.write(image, "jpg", resp.getOutputStream()); } private String makeNum() {Random random = new Random(); String num = random.nextInt(9999999) + ""; StringBuffer sb = new StringBuffer(); for (int i = 0; i < 7 - num.length(); i++) {sb.append("0"); } num = sb.toString() + num; return num; }
-
重定向
resp.sendRedirect("/test");
HttpServletRequest
解决登录申请
<html> <body> <form action="${pageContext.request.contextPath}/login" method="post"> Username<input type="text" name="username"/><br> Password<input type="password" name="password"/><br> Hobby<input type="checkbox" name="hobby" value="1"/> <input type="checkbox" name="hobby" value="2"/> <input type="checkbox" name="hobby" value="3"/> <input type="submit"/> </form> </body> </html>
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"metadata-complete="true"> <servlet> <servlet-name>login</servlet-name> <servlet-class>cn.itxiaoma.servlet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> </web-app>
LoginServlet.java
package cn.itxiaoma.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; public class LoginServlet extends HttpServlet { //get 和 post 只是申请实现的不同形式,业务逻辑一样,因而能够相互调用 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); String username = req.getParameter("username"); String password = req.getParameter("password"); String[] hobby = req.getParameterValues("hobby"); System.out.println(username); System.out.println(password); System.out.println(Arrays.toString(hobby)); // req.getRequestDispatcher("/success.jsp").forward(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp); } }
Cookie
- cookie 只能保留字符串,不能保留对象
- 一个 cookie 只能保留一个信息,最大 4kb
- 一个 web 站点能够给浏览器发送多个 cookie,一个站点最多 20 个
- 浏览器最多存 300 个左右 cookie
-
cookie 不设置有效期或设为 0,敞开浏览器主动生效
req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); PrintWriter printWriter = resp.getWriter(); Cookie[] cookies = req.getCookies(); if (cookies != null) {printWriter.print("Last Time:"); for (int i = 0; i < cookies.length; i++) {Cookie cookie = cookies[i]; if (cookie.getName().equals("lastLoginTime")) {long lastLoginTime = Long.parseLong(cookie.getValue()); Date date = new Date(lastLoginTime); printWriter.write(date.toLocaleString()); } } } else {printWriter.print("First Visit."); } Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+""); resp.addCookie(cookie);
Session
服务器会给每个用户(浏览器)创立一个 Session,只有浏览器没有敞开,session 就存在
Session 和 Cookie 的区别:Cookie 由客户端创立在浏览器保留,Session 在服务器端创立和保留
Session 和 ServletContext 区别:ServletContext 作用域是全局(Web 利用),Session 作用域是会话(浏览器)
<servlet> <servlet-name>setSession</servlet-name> <servlet-class>cn.itxiaoma.servlet.SetSession</servlet-class> </servlet> <servlet-mapping> <servlet-name>setSession</servlet-name> <url-pattern>/set</url-pattern> </servlet-mapping> <servlet> <servlet-name>getSession</servlet-name> <servlet-class>cn.itxiaoma.servlet.GetSession</servlet-class> </servlet> <servlet-mapping> <servlet-name>getSession</servlet-name> <url-pattern>/get</url-pattern> </servlet-mapping> <servlet> <servlet-name>delSession</servlet-name> <servlet-class>cn.itxiaoma.servlet.DelSession</servlet-class> </servlet> <servlet-mapping> <servlet-name>delSession</servlet-name> <url-pattern>/del</url-pattern> </servlet-mapping> <!-- 设置 session 默认生效工夫 --> <session-config> <!-- 15 分钟后主动生效 --> <session-timeout>15</session-timeout> </session-config>
SetSession.java
req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); PrintWriter printWriter = resp.getWriter(); HttpSession session = req.getSession(); session.setAttribute("name", "test"); String sessionId = session.getId(); if (session.isNew()) {printWriter.write("Session 创立胜利,Id:" + sessionId); } else {printWriter.write("Session 已存在,Id:" + sessionId); }
GetSession.java
req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); PrintWriter printWriter = resp.getWriter(); HttpSession session = req.getSession(); String sessionId = session.getId(); String sessionName = (String) session.getAttribute("name"); printWriter.write("Session Id:" + sessionId); printWriter.write("Session Name:" + sessionName);
DelSession.java
HttpSession session = req.getSession(); // 删除指定 session session.removeAttribute("name"); // 手动登记 session