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
发表回复