Servlet

Servlet是sun公司开发的解决动静web的技术

Servlet有两个默认的实现类:HttpServlet、GenericServlet

开发Servlet程序的步骤:

  1. 编写一个类,实现Servlet接口
  2. 把开发好的Java类部署到web服务器中

实现了Servlet接口的java程序称为Servlet

创立HelloServlet我的项目

  1. 构建一个一般的maven我的项目,删除src文件夹,这个空的工程作为maven主工程
  2. 引入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/

  3. 新建Module子模块servlet01(maven-archetype-webapp)

父我的项目中的java子项目能够间接应用,反之不能够

问题1:子项目pom中没有parent标签

解决:在子项目的pom.xml中手动增加parent标签并刷新maven

  1. <parent>  <groupId>cn.itxiaoma</groupId>  <artifactId>HelloMaven</artifactId>  <version>1.0-SNAPSHOT</version></parent>

    问题2:子项目pom文件有一条横线并变灰

    解决:file -->setting–>maven–>Ignored Files 将清单中对应我的项目的pom.xml文件勾销选中

  2. 将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>
  3. 在java目录下新建package包cn..itxiaoma.servlet
  4. 在包下新建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);    }}
  5. 编写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>
  6. 配置Tomcat

    Run > Edit Configurations > + > Tomcat Server - Local > Application server:抉择Tomcat目录

    Deployment > + > servlet01:war exploed

    Application Context: /servlet01_war_exploded

  7. 启动测试

    http://localhost:8081/servlet...

    Servlet原理

  8. 浏览器发送http申请(service)到web容器(Tomcat)
  9. 首次拜访的申请会加载Servlet类到内存
  10. web容器生成申请(Request)和响应(Response)两个对象,并调用Servlet的service办法
  11. Request会从service拿到申请,并执行咱们重写的解决办法,失去响应信息传给Response
  12. 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=rootpassword=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);
    常见利用
  13. 向浏览器输入音讯
  14. 下载文件

    1. 获取下载文件门路,文件名
    2. 获取下载文件的输出流
    3. 创立缓冲区
    4. 获取OutputStream对象
    5. 将FileOutputStream流写入Buffer缓冲区
    6. 应用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();
  15. 验证码性能

    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;}
  16. 重定向

    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

  17. cookie只能保留字符串,不能保留对象
  18. 一个cookie只能保留一个信息,最大4kb
  19. 一个web站点能够给浏览器发送多个cookie,一个站点最多20个
  20. 浏览器最多存300个左右cookie
  21. 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();//删除指定sessionsession.removeAttribute("name");//手动登记session