JSP&Servlet学习笔记

Servlet

源码地址:https://github.com/erlieStar/servlet-learning

运行Servlet项目

以前我们调试web项目的时候,需要在本地下载一个tomcat,为了项目的复用性,方便他人快速调试,这里演示一个用maven插件启动web项目的方法

maven7

在pom文件中加入如下配置

<plugins>
    <plugin>
        <groupId>org.apache.tomcat.mavengroupId>
        <artifactId>tomcat7-maven-pluginartifactId>
        <version>2.2version>
        <configuration>
            <port>8080port>
            <path>/path>
            <uriEncoding>UTF-8uriEncoding>
            <server>tomcat7server>
        configuration>
    plugin>
plugins>

执行如下命令即可启动

mvn tomcat7:run

或者点击idea中的侧边栏
JSP&Servlet学习笔记_第1张图片
maven8

<pluginRepositories>
    <pluginRepository>
        <id>alfresco-publicid>
        <url>https://artifacts.alfresco.com/nexus/content/groups/publicurl>
    pluginRepository>
    <pluginRepository>
        <id>alfresco-public-snapshotsid>
        <url>https://artifacts.alfresco.com/nexus/content/groups/public-snapshotsurl>
        <snapshots>
            <enabled>trueenabled>
            <updatePolicy>dailyupdatePolicy>
        snapshots>
    pluginRepository>
    <pluginRepository>
        <id>beardedgeeks-releasesid>
        <url>http://beardedgeeks.googlecode.com/svn/repository/releasesurl>
    pluginRepository>
pluginRepositories>
<build>
    <finalName>servlet-learningfinalName>
    <plugins>
        <plugin>
            <groupId>org.apache.tomcat.mavengroupId>
            <artifactId>tomcat8-maven-pluginartifactId>
            <version>3.0-r1655215version>
            <configuration>
                <port>8080port>
                <path>/path>
                <uriEncoding>UTF-8uriEncoding>
                <server>tomcat8server>
            configuration>
        plugin>
    plugins>
build>

在命令行中输入如下命令

mvn tomcat8:run

或者在idea中点击如下按钮

Servlet执行过程

  1. 用户点击页面发送请求->Web服务器应用(如Apache)->Web容器应用(如tomcat)
  2. 容器创建两个对象HttpServletRequest和HttpServletResponse
  3. 根据URL找到servlet,并为请求创建或分配一个线程,将请求和响应对象传递给这个servlet线程
  4. 容器调用Servlet的service()方法,根据请求的不同类型,service()方法会调用doGet()和doPost()方法,假如请求是HTTP GET请求
  5. doGet()方法生成动态页面,并把这个对象塞到响应对象里。容器有响应对象的一个引用
  6. 线程结束,容器把响应对象装换为一个HTTP请求,把它发回给客户,然后删除请求和响应对象

容器如何找到Servlet

使用部署描述文件把URL映射到Servlet
一个Servlet可以有3个名字,(1)用户知道的URL名,(2)部署人员知道的内部名,(3)实际的文件名


<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_3_1.xsd"
         version="3.1">
  <servlet>
    
    <servlet-name>Internal Name 1servlet-name>
    
    <servlet-class>com.makenv.controller.BeerSelect1servlet-class>
  servlet>
  
  <servlet-mapping>
    
    <servlet-name>Internal Name 1servlet-name>
    
    <url-pattern>/SelectBeer1.dourl-pattern>
  servlet-mapping>

  <servlet>
    <servlet-name>Internal Name 2servlet-name>
    <servlet-class>com.makenv.controller.BeerSelect2servlet-class>
  servlet>

  <servlet-mapping>
    <servlet-name>Internal Name 2servlet-name>
    <url-pattern>/SelectBeer2.dourl-pattern>
  servlet-mapping>

web-app>

根据url-pattern->servlet-name->servlet-class的三级映射关系,容器即可根据用户输入的URL找到对应的Servlet

实战MVC

使用servlet的请求过程

  1. 浏览器把请求数据发送给容器
  2. 容器根据URL找到正确的servlet,并把请求传递给这个servlet
  3. servlet调用BeerExpert寻求帮助
  4. servlet输出响应(打印建议)
  5. 容器把这个页面返回给用户

使用servlet和jsp的请求过程

  1. 浏览器把请求数据发送给容器
  2. 容器根据URL找到正确的servlet,并把请求传递给这个servlet
  3. servlet调用BeerExpert寻求帮助
  4. 这个“专家”类返回一个回答,servlet把这个回答增加到请求对象
  5. servlet把请求转发给JSP
  6. JSP从请求对象得到回答
  7. JSP为容器生成一个页面
  8. 容器把这个页面返回给用户

form1.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>Beer Selection Pageh1>
    <form method="post" action="SelectBeer1.do">
        Select beer
        <select name="color" size="1">
            <option value="light">lightoption>
            <option value="amber">amberoption>
            <option value="brown">brownoption>
            <option value="dark">darkoption>
        select>
        <input type="submit">
    form>
body>
html>

result.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.util.*" %>
<html>
<head>
    <title>Titletitle>
head>
<body>
    <%
        List styles = (List)request.getAttribute("styles");
        Iterator it = styles.iterator();
        while (it.hasNext()) {
            out.print("<br>try: " + it.next());
        }
    %>
body>
html>

BeerExpert.java

public class BeerExpert {

    //获得品牌
    public List getBrands(String color) {
        List brands = new ArrayList();
        if (color.equals("amber")) {
            brands.add("Jack Amber");
            brands.add("Red Moose");
        } else {
            brands.add("Jail Pale Ale");
            brands.add("Gout Stout");
        }
        return brands;
    }
}

BeerSelect1.java(只使用servlet)

public class BeerSelect1 extends HttpServlet {

    //使用doPost来处理Http请求,因为Html表单指出method = POST
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();
        out.println("Beer Selection Advice
"
); String colorValue = req.getParameter("color"); BeerExpert be = new BeerExpert(); List result = be.getBrands(colorValue); Iterator it = result.iterator(); while (it.hasNext()) { out.print("
try: "
+ it.next()); } } }

BeerSelect2.java(使用servlet和jsp)

public class BeerSelect2 extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String c = req.getParameter("color");
        BeerExpert be = new BeerExpert();
        List result = be.getBrands(c);

        //为请求对象增加一个属性,供JSP使用
        req.setAttribute("styles", result);

        //为JSP实例化一个请求分派器
        RequestDispatcher view = req.getRequestDispatcher("result.jsp");
        //使用请求分派器要求容器准备好JSP,并向JSP发送请求和响应
        view.forward(req, resp);
    }
}

请求和响应

ServletConfig对象

  • 每个servlet有一个ServletConfig对象
  • 用于向servlet传递部署时信息(例如,数据库或企业bean的查找名),而你不想把这个信息硬编码到servlet中(servlet初始化参数)
  • 用于访问ServletContext
  • 参数在部署描述文件中配置

ServletContext

  • 每个Web应用有一个ServletContext
  • 用于访问Web应用参数(也在部署描述文件中配置)
  • 相当于应用中的一个公告栏,可以在这里放消息(称为属性),应用的其他部分也可以访问这些消息
  • 用于得到服务器信息,包括容器的名字和版本,以及所支持API的版本等
    JSP&Servlet学习笔记_第2张图片
    除了参数,还能从请求对象得到什么?
//客户的平台和浏览器信息
String client = request.getHeader("User-Agent");
//与请求相关的cookie
Cookie[] cookies = request.getCookies();
//与客户相关的会话
HttpSession session = request.getSession();
//请求的HTTP方法
String theMethod = request.getMethod();
//请求的输入流
InputStream input = request.getInputStream();
//告诉浏览器这是一个html文件
response.setContentType("text/html");
//获取输出对象
PrintWriter out = response.getWriter();
//也可以使用响应设置其他首部,发送错误,以及增加cookie

属性和监听者

我想在部署描述文件(web.xml)中放入email地址,这样servlet就能以某种方式从DD“读取”email地址,而不是直接写在servlet中,如下

PrintWriter out = response.getWriter();
out.println("[email protected]");

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_3_1.xsd"
         version="3.1">

  <context-param>
    <param-name>adminEmailparam-name>
    <param-value>[email protected]param-value>
  context-param>
 
  <servlet>
    <servlet-name>BeerParamTestsservlet-name>
    <servlet-class>com.makenv.controller.TestInitParamsservlet-class>
    <init-param>
      <param-name>adminEmailparam-name>
      <param-value>[email protected]param-value>
    init-param>
    <init-param>
      <param-name>mainEmailparam-name>
      <param-value>[email protected]param-value>
    init-param>
  servlet>

  <servlet-mapping>
    <servlet-name>BeerParamTestsservlet-name>
    <url-pattern>/Tester.dourl-pattern>
  servlet-mapping>
 

web-app>

TestInitParams.java

public class TestInitParams extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();
        out.println("test init parameters
"
); Enumeration e = getServletConfig().getInitParameterNames(); while (e.hasMoreElements()) { out.println("
servlet param name = "
+ e.nextElement() + "
"
); } //获取servlet初始化参数 out.println("servlet amdin email is " + getServletConfig().getInitParameter("adminEmail")); out.println("
"
); //获取上下文初始化参数 out.println("context admin email is " + getServletContext().getInitParameter("adminEmail")); out.println("
"
); out.println("servlet main email is " + getServletConfig().getInitParameter("mainEmail")); } }

新问题来了,这些初始化参数只能是String,如果我想用一个数据库DataSource来出初始化我的应用,以便所有servlet都能使用,该怎么办?谁将String参数装换成由Web各部分共享的一个具体DataSource引用呢?不能把代码放在servlet中,因为你选择谁作为第一个servlet来查找DataSource并把它存储在一个属性中呢?我们可以使用ServletContextListener

上下文初始化时得到通知(应用得到部署)

  • 从ServletContext得到上下文初始化参数
  • 使用初始化参数查找名建立一个数据库连接
  • 把数据库连接存储为一个属性,使得Web应用的各个部分都能访问

上下文撤销时得到通知(应用取消部署或结束)

  • 关闭数据库连接

web.xml


<web-app>

  <context-param>
    <param-name>breedparam-name>
    <param-value>Great Daneparam-value>
  context-param>
  
  <servlet>
    <servlet-name>ListenerTesterservlet-name>
    <servlet-class>com.makenv.controller.ListenerTesterservlet-class>
  servlet>
  
  <servlet-mapping>
    <servlet-name>ListenerTesterservlet-name>
    <url-pattern>/ListenTest.dourl-pattern>
  servlet-mapping>
  
  <listener>
    <listener-class>com.makenv.listener.MyServletContextListenerlistener-class>
  listener>

web-app>

MyServletContextListener.java

public class MyServletContextListener implements ServletContextListener {
    public void contextInitialized(ServletContextEvent sce) {
        //由事件得到ServletContext
        ServletContext sc = sce.getServletContext();
        String dogBreed = sc.getInitParameter("breed");
        Dog d = new Dog(dogBreed);
        sc.setAttribute("dog", d);
    }

    public void contextDestroyed(ServletContextEvent sce) {

    }
}

ListenerTester.java

public class ListenerTester extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();

        out.println("test context attributes set by listener
"
); Dog dog = (Dog)getServletContext().getAttribute("dog"); out.println("Dog's breed is: " + dog.getBreed()); } }

会话管理

HTTP协议使用的无状态连接,为了让容器知道客户是谁,可以使用会话,过程很简单,对客户的第一个请求,容器会生成一个唯一的会话ID,并通过响应把它返回给客户。客户再在以后的每一个请求中发回这个会话ID。容器看到ID后,就会找到匹配的会话,并把这个会话与请求关联。容器必须以某种方式把会话ID作为响应的一部分交给客户,而客户必须把会话ID作为请求的一部分发回。最简单而且最常用的方式是通过cookie交换这个会话ID信息

在响应中发送一个会话cookie

HttpSession session = request.getSession();

这个方法不止是创建一个会话,在请求上第一次调用这个方法时,会导致随响应发送一个cookie。当你请求会话时,容器会帮你做这些事

  1. 建立新的HttpSession对象
  2. 生成唯一的会话ID
  3. 建立新的Cookie对象
  4. 把会话ID与cookie关联
  5. 在响应中设置Cookie(在Set-Cookie首部下)

从请求中得到会话ID

HttpSession session = request.getSession();
if (请求包含一个会话ID cookie) {
    找到该ID匹配的会话
} else if (没有会话ID cookie OR 没有与此会话ID匹配的当前会话) {
    创建一个新会话
}

HttpSession常用方法

方法名 解释
getCreationTime 返回第一次创建会话的时间
getLastAccessedTime 返回最后一次得到有此会话ID的请求的时间(毫秒数)
setMaxInactiveInterval 对于此会话,指定用户请求的最大间隔时间,如果超过指定时间,客户未对此会话做任何请求,就会导致会话被撤销。可以用这个方法减少服务器中无用会话的个数
getMaxInactiveInterval 对于此会话,返回客户请求的最大间隔时间(秒数)
invalidate 结束会话。当前存储在这个会话中的所有会话属性也会解除绑定

会话有三种死法

  1. 超时
  2. 在会话对象上调用invalidate()
  3. 应用结束(崩溃或取消部署)

我们在login.html页面输入用户名和密码,然后在另一个页面打印用户名和密码
其中用户名存在cookie中,而password则调用session.setAttribute(“password”, password)存储,可以看到跳转到checkcookie.do页面username和password都取出来了,关闭浏览器,不登录直接访问checkcookie.do页面,可以看到只取出来用户名,而密码没有值,因为session的存活时间是一次会话
login.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>Beer Selection Pageh1>
    <form method="post" action="cookietest.do">
        用户名:<input type="text" name="username"><br>
        密码:<input type="text" name="password">
        <input type="submit">
    form>
body>
html>

CookieTest.java

//注意加上/
@WebServlet("/cookietest.do")
public class CookieTest extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.setContentType("text/html");
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        Cookie cookie = new Cookie("username", username);
        //在客户端上存活30分钟
        cookie.setMaxAge(30 * 60);
        resp.addCookie(cookie);

        HttpSession session = req.getSession();
        //设置会话的有效时间为30 * 60
        session.setMaxInactiveInterval(30 * 60);
        session.setAttribute("password", password);

        RequestDispatcher view = req.getRequestDispatcher("cookieresult.jsp");
        view.forward(req, resp);
    }
}

cookieresult.jsp



click here


CheckCookie.java

//注意加上/
@WebServlet("/checkcookie.do")
public class CheckCookie extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();
        Cookie[] cookies = req.getCookies();

        for (int i=0; i<cookies.length; i++) {
            Cookie cookie = cookies[i];
            if (cookie.getName().equals("username")) {
                String username = cookie.getValue();
                out.println("Hello " + username);
                break;
            }
        }

        HttpSession session = req.getSession();
        out.println("your password is " + session.getAttribute("password"));
    }
}

过滤器和包装器

想跟踪访问某些servlet的用户,可以使用过滤器
请求过滤器可以

  1. 完成安全检查
  2. 重新格式化请求首部或体
  3. 建立请求审计或日志

响应过滤器可以

  1. 压缩响应流
  2. 追加或修改响应流
  3. 创建一个完全不同的响应

建立请求跟踪过滤器
web.xml


<web-app>

  
  <filter>
    <filter-name>BeerRequestfilter-name>
    <filter-class>com.makenv.filter.BeerRequestFilterfilter-class>
    
    <init-param>
      <param-name>LogFileNameparam-name>
      <param-value>UserLog.txtparam-value>
    init-param>
  filter>

  
  <filter-mapping>
    <filter-name>BeerRequestfilter-name>
    <url-pattern>*.dourl-pattern>
  filter-mapping>

  
  <filter-mapping>
    <filter-name>BeerRequestfilter-name>
    
    <servlet-name>Internal Name 1servlet-name>
  filter-mapping>

web-app>

BeerRequestFilter.java

public class BeerRequestFilter implements Filter {

    /*
     * 记录访问的用户
     */
    private FilterConfig filterConfig;

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest)request;
        String name = httpServletRequest.getRemoteUser();
        if (name != null) {
            filterConfig.getServletContext().log("User" + name + "is updating");
        }
        chain.doFilter(request, response);
    }

    public void destroy() {
        //完成清理工作
    }
}

如果你想创建定制请求或响应对象,只需要派生某个便利请求或响应“包装器”类就行了,Sun提供了4个遍历类

ServletRequestWrapper
HttpServletRequestWrapper
ServletResponseWrapper
HttpServletResponseWrapper

JSP

JSP指令

  • page指令:通常位于jsp页面的顶端,同一个页面可以有多个page指令
  • include指令:将一个外部文件嵌入到当前JSP文件中,同时解析这个页面中的JSP语句
  • taglib指令:使用标签库定义新的自定义标签,在JSP页面中启用定制行为

JSP基本语法

  • JSP脚本:在JSP页面中执行的Java代码,<% Java代码 %>
  • JSP声明:在JSP页面中定义变量或者方法,<%! Java代码 %>
  • JSP表达式:在JSP页面中执行的表达式<% =表达式 %>表达式不以分号结束

JSP页面的生命周期

JSP&Servlet学习笔记_第3张图片

get和post的区别

JSP&Servlet学习笔记_第4张图片

redirect(重定向)和forward(页面转发)

request:浏览器地址栏中的url会变化,修改提交的request数据无法传到重定向的地址。因为重定向后重新进行request(request无法共享)
forward:浏览器地址栏url不变,request可以共享

JSP内置对象

Servlet和JSP内置对象的对应关系
JSP&Servlet学习笔记_第5张图片

session

JSP&Servlet学习笔记_第6张图片
如果把会话相关的页面都关了,本次会话结束,只要有一个页面还打开着,本次会话就没有结束,长时间不操作,session也会失效,应该是设置了session的生存期限
JSP&Servlet学习笔记_第7张图片
JSP&Servlet学习笔记_第8张图片
创建新的会话并不意味着旧的会话已经结束,除非它已经超时,原有旧会话才会结束
JSP&Servlet学习笔记_第9张图片

application

JSP&Servlet学习笔记_第10张图片

page

page对象就是指向当前JSP页面本身,有点像类中的this指针,它是java.lang.Object类的实例

pageContext

JSP&Servlet学习笔记_第11张图片

config

JSP&Servlet学习笔记_第12张图片

exception

JSP&Servlet学习笔记_第13张图片

JSP动作元素

JSP&Servlet学习笔记_第14张图片
JSP&Servlet学习笔记_第15张图片
login.jsp

<h1>系统登录h1>
<form action="dologin.jsp?name=urlname" method="post">
    <table>
        <tr>
            <td>用户名td>
            <td><input type="text" name="username"/>td>
        tr>
        <tr>
            <td>密码td>
            <td><input type="text" name="password"/>td>
        tr>
        <tr>
            <td colspan="2" align="center"><input type="submit" value="提交"/>td>
        tr>
    table>
form>

dologin.jsp

<body>
    <%--这里取四次只是为了同时演示4种情况--%>
    <jsp:useBean id="myUser1" class="com.makenv.po.User" scope="page"/>
    <jsp:useBean id="myUser2" class="com.makenv.po.User" scope="page"/>
    <jsp:useBean id="myUser3" class="com.makenv.po.User" scope="page"/>
    <jsp:useBean id="myUser4" class="com.makenv.po.User" scope="page"/>
    <h4>根据表单自动匹配所有的属性h4>
    <jsp:setProperty name="myUser1" property="*"/>
    用户名:<%=myUser1.getUsername()%><br>
    密码:<%=myUser1.getPassword()%><br><hr>
    <h4>根据表单自动匹配部分的属性h4>
    <jsp:setProperty name="myUser2" property="username"/>
    用户名:<%=myUser2.getUsername()%><br>
    密码:<%=myUser2.getPassword()%><br><hr>
    <h4>跟表单无关,通过手工赋值给属性h4>
    <jsp:setProperty name="myUser3" property="username" value="admin"/>
    <jsp:setProperty name="myUser3" property="password" value="456"/>
    用户名:<%=myUser3.getUsername()%><br>
    密码:<%=myUser3.getPassword()%><br><hr>
    <h4>通过URL传参数给属性赋值h4>
    <jsp:setProperty name="myUser4" property="username" param="name"/>
    用户名:<%=myUser4.getUsername()%><br><hr>
    <h4>通过getProperty获取属性h4>
    <jsp:getProperty name="myUser1" property="username"/>
body>

页面
JSP&Servlet学习笔记_第16张图片

JavaBean的四个作用域范围

JSP&Servlet学习笔记_第17张图片

JSP状态管理

由于http协议的无状态性,保存用户的状态有两大机制,session

cookie

JSP&Servlet学习笔记_第18张图片
JSP&Servlet学习笔记_第19张图片
JSP&Servlet学习笔记_第20张图片

session和cookie的对比

JSP&Servlet学习笔记_第21张图片

cookie的使用

login.jsp保存用户登录的信息,跳转到dologin.jsp,在users.jsp中读取cookie中的信息并显示出来
login.jsp

<body>
<h1>用户登录h1>
<hr>
<%
  // 如果能从cookie中读取到用户信息,则直接显示在登录页面中
  request.setCharacterEncoding("utf-8");
  String username="";
  String password = "";
  Cookie[] cookies = request.getCookies();
  if(cookies != null && cookies.length > 0) {
       for(Cookie c:cookies) {
          if(c.getName().equals("username")) {
               username =  URLDecoder.decode(c.getValue(),"utf-8");
          }
          if(c.getName().equals("password")) {
               password =  URLDecoder.decode(c.getValue(),"utf-8");
          }
       }
  }
%>
<form name="loginForm" action="dologin.jsp" method="post">
   <table>
     <tr>
       <td>用户名:td>
       <td><input type="text" name="username" value="<%=username %>"/>td>
     tr>
     <tr>
       <td>密码:td>
       <td><input type="password" name="password" value="<%=password %>" />td>
     tr>
     <tr>
       <td colspan="2"><input type="checkbox" name="isUseCookie" checked="checked"/>十天内记住我的登录状态td>
     tr>
     <tr>
       <td colspan="2" align="center"><input type="submit" value="登录"/><input type="reset" value="取消"/>td>
     tr>
   table>
form>
body>

dologin.jsp

<body>
<h1>登录成功h1>
<hr>
<br>
<% 
   request.setCharacterEncoding("utf-8");
   //首先判断用户是否选择了记住登录状态
   String[] isUseCookies = request.getParameterValues("isUseCookie");
   if(isUseCookies != null && isUseCookies.length > 0) {
      //把用户名和密码保存在Cookie对象里面
      String username = URLEncoder.encode(request.getParameter("username"),"utf-8");
      //使用URLEncoder解决无法在Cookie当中保存中文字符串问题
      String password = URLEncoder.encode(request.getParameter("password"),"utf-8");
      
      Cookie usernameCookie = new Cookie("username",username);
      Cookie passwordCookie = new Cookie("password",password);
      usernameCookie.setMaxAge(864000);
      passwordCookie.setMaxAge(864000);//设置最大生存期限为10天
      response.addCookie(usernameCookie);
      response.addCookie(passwordCookie);
   } else {
      Cookie[] cookies = request.getCookies();
      if(cookies != null && cookies.length > 0) {
         for(Cookie c:cookies) {
            if(c.getName().equals("username")||c.getName().equals("password")) {
                c.setMaxAge(0); //设置Cookie失效
                response.addCookie(c); //重新保存。
            }
         }
      }
   }
%>
<a href="users.jsp" target="_blank">查看用户信息a>
body>

users.jsp

<body>
<h1>用户信息h1>
<hr>
<%
  //从cookie中读取用户信息,并且显示出来
  request.setCharacterEncoding("utf-8");
  String username="";
  String password = "";
  Cookie[] cookies = request.getCookies();
  if(cookies != null && cookies.length > 0) {
       for(Cookie c:cookies) {
          if(c.getName().equals("username")) {
               username = URLDecoder.decode(c.getValue(),"utf-8");
          }
          if(c.getName().equals("password")) {
               password = URLDecoder.decode(c.getValue(),"utf-8");
          }
       }
  }
%>
<br>
     用户名:<%=username %><br>
     密码:<%=password %><br>
body>

JSP指令与动作元素

include指令和include动作使用如下

<body>
  <h1>Include指令h1>
  <hr>
  <%@ include file="date.jsp"%>
  <%--flush被包含的页面是否从缓冲区读取--%>
  <jsp:include page="date.jsp" flush="false"/>
body>

include指令和include动作比较
JSP&Servlet学习笔记_第22张图片

forward和param动作

<%--跳转指令,下面这两种语法等同--%>
<%--里面第一个email是为了增加一个email属性,第二个password是把login.jsp里面的password参数改为888888--%>
<jsp:forward page="users.jsp">
  <jsp:param name="email" value="[email protected]"/>
  <jsp:param name="password" value="888888"/>
jsp:forward>
<%
  request.getRequestDispatcher("/users.jsp").forward(request,response);
%>

参考博客

maven插件
[1]https://zhuanlan.zhihu.com/p/31739991
[2]https://www.cnblogs.com/JAYIT/p/9366060.html

你可能感兴趣的:(Spring,MVC)