JSP

什么是jsp

jsp 的全称是 java server pages。Java 的服务器页面。
jsp 的主要作用是代替 Servlet 程序回传 html 页面的数据。
因为 Servlet 程序回传 html 页面数据是一件非常繁锁的事情。开发成本和维护成本都极高。

jsp的本质是什么

jsp 页面本质上是一个 Servlet 程序。
当我们第一次访问 jsp 页面的时候。Tomcat 服务器会帮我们把 jsp 页面翻译成为一个 java 源文件。并且对它进行编译成 为.class 字节码程序。
我们跟踪原代码发现,HttpJspBase 类。它直接地继承了 HttpServlet 类。也就是说。jsp 翻译出来的 java 类,它间接了继承了 HttpServlet 类。也就是说,翻译出来的是一个 Servlet 程序

jsp的三种语法

jsp 的 page 指令可以修改 jsp 页面中一些重要的属性,或者行为。

<%@ pagecontentType="text/html;charset=UTF-8" language="java" %>

属性 含义
language 表示jsp翻译后是什么语言文件,暂时只支持java
contentType 表示jsp返回的数据类型是什么,也是源码中 response.setContentType()参数值
pageEncoding 表示当前 jsp 页面文件本身的字符集
import 属性 跟 java 源代码中一样。用于导包,导类。
autoFlush 属性 设置当 out 输出流缓冲区满了之后,是否自动刷新冲级区。默认值是 true。
buffer 属性 设置 out 缓冲区的大小。默认是 8kb
errorPage 属性 设置当 jsp 页面运行时出错,自动跳转去的错误页面路径。
isErrorPage 设置当前 jsp 页面是否是错误信息页面。默认是 false。如果是 true 可以获取异常信息
session 设置访问当前 jsp 页面,是否会创建 HttpSession 对象。默认是 true
extends 设置 jsp 翻译出来的 java 类默认继承谁

errorPage表示错误后自动跳转去的路径 ,这个路径一般都是以斜杠打头,它表示请求地址为 http://ip:port/工程路径/

jsp中常用脚本

  • <%! 声明 java 代码 %>:可以给 jsp 翻译出来的 java 类定义属性和方法甚至是静态代码块。内部类等。
  • <%=表达式%>:jsp 页面上输出数据(特点如下)
    • 所有的表达式脚本都会被翻译到_jspService() 方法中
    • 表达式脚本都会被翻译成为 out.print()输出到页面上
    • 由于表达式脚本翻译的内容都在_jspService() 方法中,所以_jspService()方法中的对象都可以直接使用
    • 表达式脚本中的表达式不能以分号结束
  • <% java 语句 %>:可以在 jsp 页面中,编写我们自己需要的功能(写的是 java 语句)
    • 1、代码脚本翻译之后都在_jspService 方法中
    • 2、代码脚本由于翻译到_jspService()方法中,所以在_jspService()方法中的现有对象都可以直接使用。
    • 3、还可以由多个代码脚本块组合完成一个完整的 java 语句。
    • 4、代码脚本还可以和表达式脚本一起组合使用,在 jsp 页面上输出数据
  1. <%@ page import="java.util.HashMap" %>
  2. <%@ page import="java.util.Map" %>
  3. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  4. <html>
  5. <head>
  6. <title>Title</title>
  7. </head>
  8. <body>
  9. <h1>这是JSP界面</h1>
  10. <%--声明类属性--%>
  11. <%!
  12. private Integer id;
  13. private String name;
  14. private static Map<String,Object> map;
  15. %>
  16. <%--声明static静态代码块--%>
  17. <%!
  18. static {
  19. map = new HashMap<String,Object>();
  20. map.put("key1", "value1");
  21. map.put("key2", "value2");
  22. map.put("key3", "value3");
  23. }
  24. %>
  25. <%--3、声明类方法--%>
  26. <%!
  27. public int abc(){
  28. return 12;
  29. }
  30. %>
  31. <%--4、声明内部类--%>
  32. <%!
  33. public static class A {
  34. private Integer id = 12;
  35. private String abc = "abc";
  36. }
  37. %>
  38. </body>
  39. </html>
 <%@ page import="java.util.HashMap" %>
 <%@ page import="java.util.Map" %>
 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 <html>
 <head>
     <title>Title</title>
 </head>
 <body>
 <h1>这是JSP界面</h1>
 <%--声明类属性--%>
 <%!
     private Integer id;
     private String name;
     private static Map<String,Object> map;
 %>
 <%--声明static静态代码块--%>
 <%!
     static {
         map = new HashMap<String,Object>();
         map.put("key1", "value1");
         map.put("key2", "value2");
         map.put("key3", "value3");
     }
 %>
 <%--3、声明类方法--%>
 <%!
     public int abc(){
         return 12;
     }
 %>
 <%--4、声明内部类--%>
 <%!
     public static class A {
         private Integer id = 12;
         private String abc = "abc";
     }
 %>
 <%=12 %><br>

 <%=12.12 %><br>

 <%="我是字符串" %> <br>

 <%=map%> <br>

 <%=request.getParameter("username")%>

 <%--1.代码脚本----if 语句--%>
 <%
     int i = 13 ;
     if (i == 12) {
 %>
 <h1>国哥好帅</h1>
 <% }
     else {
 %>
 <h1>国哥又骗人了!</h1>
 <% } %> <br>
 <%--2.代码脚本----for 循环语句--%>
 <table border="1" cellspacing="0">
     <% for (int j = 0; j < 10; j++) {
     %> <tr><td>第
     <%=j + 1%>行</td> </tr>
     <% } %>
 </table>
 <%--3.翻译后 java 文件中_jspService 方法内的代码都可以写--%>
 <% String username = request.getParameter("username");
     System.out.println("用户名的请求参数值是:" + username);
 %>
 </body>
 </html>

jsp的九大内置对象

request 请求对象
respond 响应对象
pageContext jsp的上下文对象
session 会话对象
application ServletContext对象
config ServletConfig对象
out jsp输出流对象
page 指向当前jsp的对象
exception 异常对象

jsp四大域对象

作用
pageContext(PageContextImpl 类) 当前 jsp 页面范围内有效
request (HttpServletRequest 类) 一次请求内有效
session (HttpSession 类) 一个会话范围内有效(打开浏览器访问服务器,直到关闭浏览器)
application (ServletContext 类) 整个 web 工程范围内都有效(只要 web 工程不停止,数据都在)

jsp中的out输出和response.getWriter输出的区别

在jsp文件执行结束之前,response操作会先把数据刷新到response缓冲区,而out操作将会在文件执行完毕前调用out.flush()操作,将out的数据刷新到response缓冲区

  • response 中表示响应,我们经常用于设置返回给客户端的内容(输出) ,out 也是给用户做输出使用的。
  • 由于 jsp 翻译之后,底层源代码都是使用 out 来进行输出,所以一般情况下。我们在 jsp 页面中统一使用 out 来进行输出。避 免打乱页面输出内容的顺序

out.write()和out.print()的区别

  • out.write()输出字符串没问题
  • out.print()输出任意数据都没有问题(都转换成为字符串后调用write输出)
  • 在 jsp 页面中,可以统一使用 out.print()来进行输出

JSP常用标签

静态包含

  • jsp静态包含<%@ include file=””%>就是静态包含file属性指定你要包含的jsp页面的路径
    地址中第一个斜杠/表示为 http://ip:port/工程路径/ 映射到代码的web目录
  • 静态包含的特点

    • 静态包含不会翻译被包含的jsp页面
    • 静态包含其实是把被包含的jsp页面的代码拷贝到包含的位置执行输出。


    动态包含

  • 动态包含:<jsp:include page=""></jsp:include>

    • page属性是指定你要包含的jsp页面的路径
    • 动态包含也可以像静态包含一样。把被包含的内容执行输出到包含位置
  • 动态包含的特点
  • 动态包含会把包含的jsp页面也翻译成为java代码
    • 动态包含底层代码使用如下代码去调用被包含的jsp页面执行输出JspRuntimeLibrary.include(request, response, "/include/footer.jsp", out, false);
  • 动态包含,还可以传递参数

请求转发

  • <jsp:forward page=""></jsp:forward>是请求转发标签,它的功能就是请求转发page属性设置请求转发的路径

main.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    头部信息<br>
    主题内容<br>

<%@include file="footer.jsp"%>
</body>
</html>

footer.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
脚页信息<br>
</body>
</html>

Listener监听器

1、Listener 监听器它是 JavaWeb 的三大组件之一。JavaWeb 的三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器。

2、Listener 它是 JavaEE的规范,就是接口

3、监听器的作用是,监听某种事物的变化。然后通过回调函数,反馈给客户(程序)去做一些相应的处理。

ServletContextListener 监听器

ServletContextListener 它可以监听 ServletContext 对象的创建和销毁。

ServletContext 对象在 web 工程启动的时候创建,在 web 工程停止的时候销毁。

监听到创建和销毁之后都会分别调用 ServletContextListener 监听器的方法反馈。

public interface ServletContextListener extends EventListener {
/**
* 在 ServletContext 对象创建之后马上调用,做初始化 
*/ 
public void contextInitialized(ServletContextEvent sce);
/**
* 在 ServletContext 对象销毁之后调用 
*/ 
public void contextDestroyed(ServletContextEvent sce);

jsp页面中的html内容呗翻译到Servlet程序的service方法中原样输出,这就是jsp专门用来输出html页面的Servlet程序

jsp 文件头部声明介绍

<%@ page language=”java” contentType=”text/html; charset=UTF-8” pageEncoding=”UTF-8” %>
这是 jsp 文件的头声明。表示这是 jsp 页面。
language 属性 值只能是 java。 表示翻译的得到的是 java 语言的
contentType 属性 设置响应头 contentType 的内容
pageEncoding 属性 设置当前 jsp 页面的编码
import 属性 给当前 jsp 页面导入需要使用的类包
autoFlush 属性 设置是否自动刷新 out 的缓冲区,默认为 true
buffer 属性 设置 out 的缓冲区大小。默认为 8KB
errorPage 属性 设置当前 jsp 发生错误后,需要跳转到哪个页面去显示错误信息
isErrorPage 属性 设置当前 jsp 页面是否是错误页面。是的话,就可以使用 exception 异常对象
session 属性 设置当前 jsp 页面是否获取 session 对象,默认为 true
extends 属性 给服务器厂商预留的jsp 默认翻译的 servlet 继承于什么类

jsp 中的三种脚本介绍

第一种:
<%! java 代码 %>
 1.我们可以定义全局变量。
 2.定义 static 静态代码块
 3.定义方法 
 4.定义内部类 几乎可以写在类的内部写的代码,都可以通过声明脚本来实现
第二种:
  <%=表达式 %> 
    表达式脚本 用于向页面输出内容。 
    表达式脚本 翻译到 Servlet 程序的 service 方法中 以 out.print() 打印输出 
    out 是 jsp 的一个内置对象,用于生成 html 的源代码 
    注意:表达式不要以分号结尾,否则会报错 表达式脚本可以输出任意类型
第三种:
    <% java 代码 %> 
      代码脚本里可以书写任意的 java 语句。
      代码脚本的内容都会被翻译到 service 方法中。 
      所以 service 方法中可以写的 java 代码,都可以书写到代码脚本中

jsp中九大内置对象

request 对象 请求对象,可以获取请求信息
response 对象 响应对象。可以设置响应信息
pageContext 对象 当前页面上下文对象。可以在当前上下文保存属性信息
session 对象 会话对象。可以获取会话信息。
exception 对象 异常对象只有在 jsp 页面的 page 指令中设置 isErrorPage=“true” 的时候才会存在
application 对象 ServletContext 对象实例,可以获取整个工程的一些信息。
config 对象 ServletConfig 对象实例,可以获取 Servlet 的配置信息
out 对象 输出流。
page 对象 表示当前 Servlet 对象实例(无用,用它不如使用 this 对象)。
九大内置对象,都是我们可以在【代码脚本】中或【表达式脚本】中直接使用的对

JSP四大域对象

pageContext 可以保存数据在同一个 jsp 页面中使用
request 可以保存数据在同一个 request 对象中使用。经常用于在转发的时候传递数据
session 可以保存在一个会话中使用
application(ServletContext) 就是 ServletContext 对象

JSTL标签库

JSTL 标签库 全称是指 JSP Standard Tag Library JSP 标准标签库。是一个不断完善的开放源代码的 JSP 标签库。EL 表达式主要是为了替换 jsp 中的表达式脚本,而标签库则是为了替换代码脚本。这样使得整个 jsp 页面变得更佳简洁。
JSTL 由五个不同功能的标签库组成

功能范围 URI 前缀
核心标签库—重点 http://java.sun.com/jsp/jstl/core c
格式化 http://java.sun.com/jsp/jstl/fmt fmt
函数 http://java.sun.com/jsp/jstl/functions fn
数据库(不使用) http://java.sun.com/jsp/jstl/sql sql
XML(不使用) http://java.sun.com/jsp/jstl/xml x

JSTL 标签库的使用步骤

1、先导入 jstl 标签库的 jar 包。
taglibs-standard-impl-1.2.1.jar
taglibs-standard-spec-1.2.1.jar
2、第二步,使用 taglib 指令引入标签库。
<%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core“ %>

core核心库使用

作用:set 标签可以往域中保存数据
作用:if 标签用来做 if 判断
作用:多路判断。跟 switch … case
作用:遍历输出使用。

<body>

    <%--1.<c:set/>--%>
    保存之前:${requestScope.abc}<br>
    <%--  scope表示设置在哪个域  var设置键 value设置值  --%>
    <c:set scope="request" var="abc" value="abcvalue"/>
    保存之后:${requestScope.abc}<br>

    <%--2.<c:if>--%>
    <%-- test属性表示判断的条件(使用 EL 表达式输出)  --%>
    <c:if test="${12==12}">
        <h1>if成立</h1>
    </c:if>

    <%--3. <c:choose> <c:when> <c:otherwise>  多路判断 跟switch ... case .... default 非常接近 --%>
    <%
        request.setAttribute("height",180);
    %>
    <c:choose>
        <c:when test="${requestScope.height>190}">身高190以上</c:when>
        <c:when test="${requestScope.height>180}">身高180以上</c:when>
        <c:otherwise>其他</c:otherwise>
    </c:choose>

    <%--4.<c:forEach> 遍历循环--%>
    <%
        request.setAttribute("arr",new String[]{"123","232","453"});

        HashMap<String, Object> map = new HashMap<>();
        map.put("key1","value1");
        map.put("key2","value2");
        map.put("key3","value3");
        request.setAttribute("map",map);

    %>
    <c:forEach begin="1" end="10" var="i">${i}<br></c:forEach>
    <c:forEach items="${requestScope.arr}" var="item">
        ${item}<br>
    </c:forEach>
    <c:forEach items="${requestScope.map}" var="entry">
        <h1>${entry.key}=${entry.value}</h1>
    </c:forEach>

</body>

文件的上传和下载

1、要有一个 form 标签,method=post 请求
2、form 标签的 encType 属性值必须为 multipart/form-data 值
3、在 form 标签中使用 input type=file 添加上传的文件
4、编写服务器代码(Servlet 程序)接收,处理上传的数据。
encType=multipart/form-data 表示提交的数据,以多段(每一个表单项一个数据段)的形式进行拼
接,然后以二进制流的形式发送给服务器

commons-fileupload.jar 常用 API 介绍说明

commons-fileupload.jar 需要依赖 commons-io.jar 这个包,所以两个包我们都要引入。
第一步,就是需要导入两个 jar 包:
commons-fileupload-1.2.1.jar
commons-io-1.4.jar

commons-fileupload.jar 和 commons-io.jar 包中,我们常用的类有哪些?

ServletFileUpload 类,用于解析上传的数据。 
FileItem 类,表示每一个表单项。 
boolean ServletFileUpload.isMultipartContent(HttpServletRequest request); 
判断当前上传的数据格式是否是多段的格式。 
public List<FileItem> parseRequest(HttpServletRequest request) 解析上传的数据 
boolean FileItem.isFormField() 判断当前这个表单项,是否是普通的表单项。还是上传的文件类型。 
true 表示普通类型的表单项 
false 表示上传的文件类型 
String FileItem.getFieldName() 
获取表单项的 name 属性值String FileItem.getString() 
获取当前表单项的值。 
String FileItem.getName(); 
获取上传的文件名 
void FileItem.write( file ); 
将上传的文件写到 参数 file 所指向抽硬盘位置 。
package com.example.JSTL1;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.File;
import java.io.IOException;
import java.util.List;

@WebServlet(name = "UploadServlet", value = "/uploadServlet")
public class UploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("文件上传过来了");
        //1.先判断上传的数据是否是多端数据(只有是多端的数据,才是文件上传的)
        if (ServletFileUpload.isMultipartContent(request)){
            //创建FileItemFactory工厂实现类
            FileItemFactory fileItemFactory = new DiskFileItemFactory();
            //创建用于解析上传数据的工具类ServletFileUpload类
            ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
            try {
                //解析上传的数据,得到每一个表单项FileItem
                List<FileItem> list = servletFileUpload.parseRequest(request);
                //循环判断,每一个表单项是普通类型,还是上传的文件
                for (FileItem fileItem:list){
                    if (fileItem.isFormField()){
                        System.out.println("表单项的 name 属性值:" + fileItem.getFieldName());
                        // 参数 UTF-8.解决乱码问题
                        System.out.println("表单项的 value 属性值:" + fileItem.getString("UTF-8"));
                    }else {
                        // 上传的文件
                        System.out.println("表单项的 name 属性值:" + fileItem.getFieldName());
                        System.out.println("上传的文件名:" + fileItem.getName());
                        fileItem.write(new File("e:\\" + fileItem.getName())); }
                    }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<form action="http://localhost:8080/JSTL1_war_exploded/uploadServlet" method="post" enctype="multipart/form-data" >
用户名:<input type="text" name="username"><br>
头像:<input type="file" name="photo"><br>
<input type="submit" value="上传"><br>
</form>
</body>
</html>

文件的下载
response.getOutputStream();
servletContext.getResourceAsStream();
servletContext.getMimeType();
response.setContentType();

response.setHeader(“Content-Disposition”, “attachment; fileName=1.jpg”);
这个响应头告诉浏览器。这是需要下载的。而 attachment 表示附件,也就是下载的一个文件。fileName=后面,
表示下载的文件名。 完成上面的两个步骤,下载文件是没问题了。但是如果我们要下载的文件是中文名的话。你会发现,下载无法正确显示出正确的中文名。 原因是在响应头中,不能包含有中文字符,只能包含 ASCII 码。

package com.example.JSTL1;

import org.apache.commons.io.IOUtils;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;

@WebServlet(name = "Download", value = "/download")
public class Download extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //1.获取下载的内容
        String downloadFileName= "2.jpg";

        //2.读取要下载的文件内容(通过ServletContext())读取;
        ServletContext servletContext = getServletContext();

        //4.在回传前告诉客户端返回的数据类型
        //获取要下载的文件类型
        String mimeType = servletContext.getMimeType("/file/" + downloadFileName);
        System.out.println(mimeType);
        response.setContentType(mimeType);

        //5.还要告诉客户端收到的数据是用于下载的
//        response.setHeader("Content-Disposition","attament;filename="+downloadFileName);
        response.setHeader("Content-Disposition","attament;filename="+ URLEncoder.encode("中国.jpg","UTF-8"));

        InputStream resourceAsStream=servletContext.getResourceAsStream("/file/"+downloadFileName);
        //获取相应的输出流
        ServletOutputStream outputStream = response.getOutputStream();
        //3.把下载的文件内容回传给客户端

        //读取输入流中的全部数据,复制给输出流
        IOUtils.copy(resourceAsStream,outputStream);


    }


}

图片.png

BeanUtils工具类

BeanUtils 工具类,它可以一次性的把所有请求的参数注入到 JavaBean 中。 (将请求过来的key和value一次性封装到JavaBean中,免去了繁琐的调用set方法)
BeanUtils 工具类,经常用于把 Map 中的值注入到 JavaBean 中,或者是对象属性值的拷贝操作。
BeanUtils 它不是 Jdk 的类。而是第三方的工具类。所以需要导包。
1、导入需要的 jar 包:
commons-beanutils-1.8.0.jar
commons-logging-1.1.1.jar
2、编写 WebUtils 工具类使用:

package com.atguigu.utils;
import org.apache.commons.beanutils.BeanUtils;
import java.util.Map;

public class WebUtils {
    /**
     * 把Map中的值注入到对应的JavaBean属性中。
     * @param value
     * @param bean
     */
    public static <T> T copyParamToBean( Map value , T bean ){
        try {
            System.out.println("注入之前:" + bean);
            /**
             * 把所有请求的参数都注入到user对象中
             */
            BeanUtils.populate(bean, value);
            System.out.println("注入之后:" + bean);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bean;
    }
}

Cookie

什么是Cookie?

  • Cookie 是服务器通知客户端保存键值对的一种技术。
  • 客户端有了 Cookie 后,每次请求都发送给服务器。
  • 每个 Cookie 的大小不能超过 4kb

Cookie的值不支持中文和特殊符号,如果有需要则应该使用BASE64进行编码

cookieServlet.java

package com.example.cookie_session;

import com.example.util.CookieUtils;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet(name = "CookieServlet", value = "/cookieServlet")
public class CookieServlet extends BaseServlet {



    protected void updateCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /** 方案一:
         * 1.先创建一个要修改的同名Cookie对象
         * 2.在构造器,同时赋予新的Cookie值
         * 3.调用respond.addCookie(cookie);通知客户端保存修改
         */
        Cookie cookie1 = new Cookie("key1", "newValue1");
        response.addCookie(cookie1);
        response.getWriter().write("Cookie"+cookie1.getName()+"已修改为"+cookie1.getValue());


        /** 方案二:
         * 1.先查找到需要修改的Cookie对象
         * 2.调用setValue()方法赋于新的Cookie值
         * 3.调用response.addCookie()通知客户端保存修改
         */
        Cookie cookie2 = CookieUtils.findCookie("key2", request.getCookies());
        cookie2.setValue("newValue2");
        response.addCookie(cookie2);
        response.getWriter().write("Cookie"+cookie2.getName()+"已修改为"+cookie2.getValue());



    }
    protected void getCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            response.getWriter().write("cookie["+cookie.getName()+"="+cookie.getValue()+"]");
        }
        Cookie iwantCookie = CookieUtils.findCookie("key1", cookies);
        response.getWriter().write("找到了Cookie"+iwantCookie.getName()+"="+iwantCookie.getValue());

    }
    protected void createCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.创建Cookie对象
        Cookie cookie = new Cookie("key1", "value1");
        //2.通知客户端保存Cookie
        response.addCookie(cookie);
        response.getWriter().write("Cookie创建成功");
        //1.创建Cookie对象
        Cookie cookie1 = new Cookie("key2", "value2");
        //2.通知客户端保存Cookie
        response.addCookie(cookie1);
        response.getWriter().write("Cookie创建成功");
    }
}

CookieUtiles.java

package com.example.util;

import javax.servlet.http.Cookie;

public class CookieUtils {
    public static Cookie findCookie(String name, Cookie[] cookies){
        if (name==null||cookies==null||cookies.length==0){
            return null;
        }
        for (Cookie cookie : cookies) {
            if(name.equals(cookie.getName())){
                return cookie;
            }
        }
        return null;
    }
}

cookie.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <base href="http://localhost:8080/cookie_session/">
<title>Cookie</title>
<style type="text/css">

    ul li {
        list-style: none;
    }

</style>
</head>
<body>
    <iframe name="target" width="500" height="500" style="float: left;"></iframe>
    <div style="float: left;">
        <ul>
            <li><a href="cookieServlet?action=createCookie" target="target">Cookie的创建</a></li>
            <li><a href="cookieServlet?action=getCookie" target="target">Cookie的获取</a></li>
            <li><a href="cookieServlet?action=updateCookie" target="target">Cookie值的修改</a></li>
            <li>Cookie的存活周期</li>
            <li>
                <ul>
                    <li><a href="" target="target">Cookie的默认存活时间(会话)</a></li>
                    <li><a href="" target="target">Cookie立即删除</a></li>
                    <li><a href="" target="target">Cookie存活3600秒(1小时)</a></li>
                </ul>
            </li>
            <li><a href="" target="target">Cookie的路径设置</a></li>
            <li><a href="" target="target">Cookie的用户免登录练习</a></li>
        </ul>
    </div>
</body>
</html>

Cookie生命控制

Cookie 的生命控制指的是如何管理 Cookie 什么时候被销毁(删除)
setMaxAge()
正数,表示在指定的秒数后过期
负数,表示浏览器一关,Cookie 就会被删除(默认值是-1)
零,表示马上删除

protected void testPath(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie cookie = new Cookie("path1", "path1");
        cookie.setPath(request.getContextPath()+"/abc");//--> /工程路径/abc
        response.addCookie(cookie);
        response.getWriter().write("创建了带有Paht属性的Cookie");

    }
    protected void defaultLife(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie cookie = new Cookie("defaultLife", "defauleLife");
        cookie.setMaxAge(-1);//设置存活时间
        response.addCookie(cookie);
    }

Session会话

什么是 Session 会话?
1、Session 就一个接口(HttpSession)。
2、Session 就是会话。它是用来维护一个客户端和服务器之间关联的一种技术。
3、每个客户端都有自己的一个 Session 会话。
4、Session 会话中,我们经常用来保存用户登录之后的信息。

如何创建 Session 和获取(id 号,是否为新)
如何创建和获取 Session。它们的 API 是一样的。
request.getSession()
第一次调用是:创建 Session 会话
之后调用都是:获取前面创建好的 Session 会话对象。

isNew(); 判断到底是不是刚创建出来的(新的)
true 表示刚创建
false 表示获取之前创建

每个会话都有一个身份证号。也就是 ID 值。而且这个 ID 是唯一的。
getId() 得到 Session 的会话 id 值。

Session 生命周期控制

public void setMaxInactiveInterval(int interval) 设置 Session 的超时时间(以秒为单位),超过指定的时长,Session就会被销毁。
值为正数的时候,设定 Session 的超时时长。
负数表示永不超时(极少使用)
public int getMaxInactiveInterval()获取 Session 的超时时间
public void invalidate() 让当前 Session 会话马上超时无效。
Session 默认的超时时长是多少!
Session 默认的超时时间长为 30 分钟。
因为在 Tomcat 服务器的配置文件 web.xml中默认有以下的配置,它就表示配置了当前 Tomcat 服务器下所有的 Session
超时配置默认时长为:30 分钟。

30

  • 如果说。你希望你的 web 工程,默认的 Session 的超时时长为其他时长。你可以在你自己的 web.xml 配置文件中做以上相同的配置。就可以修改你的 web 工程所有 Seession 的默认超时时长
  • 如果你想只修改个别 Session 的超时时长。就可以使用上面的 API。setMaxInactiveInterval(int interval)来进行单独的设置。session.setMaxInactiveInterval(int interval)单独设置超时时长。 ```java package com.example.cookie_session;

import javax.servlet.; import javax.servlet.http.; import javax.servlet.annotation.*; import java.io.IOException;

@WebServlet(name = “sessionServlet”, value = “/sessionServlet”) public class sessionServlet extends BaseServlet {

protected void deleteNow(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    HttpSession session = request.getSession();
    session.invalidate();
    response.getWriter().write("当前Session已经设置为无效");
}
protected void life3(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //先获取Session对象
    HttpSession session = request.getSession();
    //设置当前Session3秒后超时、
    session.setMaxInactiveInterval(3);
    response.getWriter().write("当前Session已经设置为3秒后超时");
}
protected void defaultLife(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //获取Session的默认超时时长为
    int maxInactiveInterval = request.getSession().getMaxInactiveInterval();
    response.getWriter().write("Sesison的默认超时时长为:"+maxInactiveInterval+"秒");
}
protected void setAttribute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.getSession().setAttribute("key1","value1");
    response.getWriter().write("已经往Session中保存了数据");
}
protected void getAttribute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Object attribute = request.getSession().getAttribute("key1");
    response.getWriter().write("从Session中获取出key1的数据是:"+attribute);

}
protected void createOrGetSession(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //创建和获取会话对象
    HttpSession session = request.getSession();
    //判断
    boolean isNew = session.isNew();
    //获取session会话的唯一标识id
    String id = session.getId();
    response.getWriter().write("得到的Session,它的ID是"+id+",这个Session是否是新创建的"+isNew);

}

}


```html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <base href="http://localhost:8080/cookie_session/">

    <title>Session</title>
<style type="text/css">

    ul li {
        list-style: none;
    }

</style>
</head>
<body>
    <iframe name="target" width="500" height="500" style="float: left;"></iframe>
    <div style="float: left;">
        <ul>
            <li><a href="sessionServlet?action=createOrGetSession" target="target">Session的创建和获取(id号、是否为新创建)</a></li>
            <li><a href="sessionServlet?action=setAttribute" target="target">Session域数据的存储</a></li>
            <li><a href="sessionServlet?action=getAttribute" target="target">Session域数据的获取</a></li>
            <li>Session的存活</li>
            <li>
                <ul>
                    <li><a href="sessionServlet?action=defaultLife" target="target">Session的默认超时及配置</a></li>
                    <li><a href="sessionServlet?action=life3" target="target">Session3秒超时销毁</a></li>
                    <li><a href="sessionServlet?action=deleteNow" target="target">Session马上销毁</a></li>
                </ul>
            </li>
            <li><a href="" target="target">浏览器和Session绑定的原理</a></li>
        </ul>
    </div>
</body>
</html>

谷歌kaptcha图片验证码的使用

谷歌验证码 kaptcha 使用步骤如下:
1、导入谷歌验证码的 jar 包 kaptcha-2.3.2.jar
2、在 web.xml 中去配置用于生成验证码的 Servlet 程序

 <servlet>
        <servlet-name>KaptchaServlet</servlet-name>
        <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>KaptchaServlet</servlet-name>
        <url-pattern>/kaptcha.jpg</url-pattern>
    </servlet-mapping>

3、在表单中使用 img 标签去显示验证码图片并使用它

 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script src="jquery-1.7.2.js"></script>
    <script type="text/javascript">
        $(function () {
            $('#code_btn').click(function () {
                this.src="${basePath}kaptcha.jpg?d="+new Date();
            });
        });
    </script>
</head>
<body>
    <form action="http://localhost:8080/cookie_session/registServlet" method="get">
        用户名:<input type="text" name="username" > <br>
        验证码:<input type="text" style="width: 80px;" name="code"><br>
        <img id="code_btn" src="http://localhost:8080/cookie_session/kaptcha.jpg" alt="" style="width: 100px; height: 28px;"> <br>
        <input type="submit" value="登录">
    </form>
</body>
</html>

4、在服务器获取谷歌生成的验证码和客户端发送过来的验证码比较使用

package com.example.cookie_session;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import static com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY;
@WebServlet(name = "RegistServlet", value = "/registServlet")
public class RegistServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String token = (String) request.getSession().getAttribute(KAPTCHA_SESSION_KEY);
        //删除Session中的验证码
        request.getSession().removeAttribute(KAPTCHA_SESSION_KEY);
        String code=request.getParameter("code");
        //获取用户名
        String username=request.getParameter("username");
        if (token!=null && token.equals(code)){
            System.out.println("保存到数据库"+username);
            response.sendRedirect(request.getContextPath()+"/ok.jsp");
        }else {
            System.out.println("请不要重复提交表单");
        }
    }
}

ps: 当遇到验证码只能刷新一次的问题时,是因为浏览器中存在缓存,会直接冲浏览器中将验证码返回,这时需要在路径后面加上时间戳。

Filter过滤器

Filter 什么是过滤器
1、Filter 过滤器它是 JavaWeb 的三大组件之一。三大组件分别是:Servlet 程序、Listener 监听器、Filter 过滤器
2、Filter 过滤器它是 JavaEE 的规范。也就是接口
3、Filter 过滤器它的作用是:拦截请求,过滤响应。
拦截请求常见的应用场景有:
1、权限检查
2、日记操作
3、事务管理
……等等
Filter 的初体验
要求:在你的 web 工程下,有一个 admin 目录。这个 admin 目录下的所有资源(html 页面、jpg 图片、jsp 文件、等等)都必须是用户登录之后才允许访问。
思考:根据之前我们学过内容。我们知道,用户登录之后都会把用户登录的信息保存到 Session 域中。所以要检查用户是否登录,可以判断 Session 中否包含有用户登录的信息即可!!!

设置配置文件

<filter>
        <!--给filter起一个别名-->
        <filter-name>AdminFilter</filter-name>
        <!--配置filter的全类名-->
        <filter-class>com.example.filter.AdminFilter</filter-class>
    </filter>
    <!--filter-mapping配置Filter过滤器的拦截路径-->
    <filter-mapping>
        <!--filter-name表示当前的拦截路径给哪个filter使用-->
        <filter-name>AdminFilter</filter-name>
        <!--url-pattern配置拦截路径   /表示请求地址为:http://ip:port/工程路径/  映射到IDEA的web目录-->
        <url-pattern>/admin/*</url-pattern>
    </filter-mapping>

编写filter过滤器服务

package com.example.filter;

import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter(filterName = "AdminFilter")
public class AdminFilter implements Filter {
    public void init(FilterConfig config) throws ServletException {
    }

    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest httpServletRequest=(HttpServletRequest) request;

        HttpSession session = httpServletRequest.getSession();
        Object user = session.getAttribute("user");
        //如果等于null说明还没登陆
        if(user==null){
            request.getRequestDispatcher("/login.jsp").forward(request,response);
            return;
        }else {
            //让程序继续往下访问用户的目标资源
            chain.doFilter(request,response);
        }
    }
}

编写登陆界面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <base href="http://localhost:8080/filter/">
</head>
<body>
    这是登录页面
    <form action="loginServlet" method="get">
        用户名:<input type="text" name="username"><br>
        密码: <input type="password" name="password"><br>
        <input type="submit">

    </form>
</body>
</html>

编写登陆的服务

package com.example.servlet;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet(name = "LoginServlet", value = "/loginServlet")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if ("1".equals(username)&&"1".equals(password)){
            request.getSession().setAttribute("user",username);
            response.getWriter().write("登陆成功");
        }else {
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }
    }
}

Filter的生命周期

Filter 的生命周期包含几个方法
1、构造器方法
2、init 初始化方法
第 1,2 步,在 web 工程启动的时候执行(Filter 已经创建)
3、doFilter 过滤方法
第 3 步,每次拦截到请求,就会执行
4、destroy 销毁
第 4 步,停止 web 工程的时候,就会执行(停止 web 工程,也会销毁 Filter 过滤器)

FilterConfig 类

FilterConfig 类见名知义,它是 Filter 过滤器的配置文件类。
Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置信息。
FilterConfig 类的作用是获取 filter 过滤器的配置内容
1、获取 Filter 的名称 filter-name 的内容
2、获取在 Filter 中配置的 init-param 初始化参数
3、获取 ServletContext 对象

public void init(FilterConfig config) throws ServletException {
//        1、获取 Filter 的名称 filter-name 的内容
        System.out.println(config.getFilterName());
//        2、获取在 web.xml 中配置的 init-param 初始化参数
        System.out.println("初始化参数username的值是"+config.getInitParameter("username"));
        System.out.println("初始化参数url的值是"+config.getInitParameter("url"));
//        3、获取 ServletContext 对象
        System.out.println(config.getServletContext());
    }

    <filter>
        <!--给filter起一个别名-->
        <filter-name>AdminFilter</filter-name>
        <!--配置filter的全类名-->
        <filter-class>com.example.filter.AdminFilter</filter-class>

        <init-param>
            <param-name>username</param-name>
            <param-value>root</param-value>
        </init-param>
        <init-param>
            <param-name>url</param-name>
            <param-value>jdbc:mysql://localhost:3306/test</param-value>
        </init-param>
    </filter>
    <!--filter-mapping配置Filter过滤器的拦截路径-->
    <filter-mapping>
        <!--filter-name表示当前的拦截路径给哪个filter使用-->
        <filter-name>AdminFilter</filter-name>
        <!--url-pattern配置拦截路径   /表示请求地址为:http://ip:port/工程路径/  映射到IDEA的web目录-->
        <url-pattern>/admin/*</url-pattern>
    </filter-mapping>

FilterChain 过滤器链

就是多个过滤器是如何一起工作的
图片.png特点:
1.在多个Filter过滤器执行的时候,他们执行的优先顺序是由他们在web.xml中从上到下配置的顺序决定
2.所有filter和目标资源默认都执行在同一个线程中
3.多个filter共同执行的时候,它们都使用同一个Request对象

Filter的拦截路径

精确匹配

<url-pattern>/target.jsp</url-pattern>
以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/target.jsp

目录匹配

<url-pattern>/admin/</url-pattern>
以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/admin/

后缀名匹配

<url-pattern>.html</url-pattern>
以上配置的路径,表示请求地址必须以.html 结尾才会拦截到
<url-pattern>
.do</url-pattern>
以上配置的路径,表示请求地址必须以.do 结尾才会拦截到
<url-pattern>.action</*url-pattern>
以上配置的路径,表示请求地址必须以.action 结尾才会拦截到
Filter 过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在!!!

ThreadLocal 的使用

ThreadLocal 的作用,它可以解决多线程的数据安全问题。
ThreadLocal 它可以给当前线程关联一个数据(可以是普通变量,可以是对象,也可以是数组,集合)
ThreadLocal 的特点:
1、ThreadLocal 可以为当前线程关联一个数据。(它可以像 Map 一样存取数据,key 为当前线程)
2、每一个 ThreadLocal 对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个
ThreadLocal 对象实例。
3、每个 ThreadLocal 对象实例定义的时候,一般都是 static 类型
4、ThreadLocal 中保存数据,在线程销毁后。会由 JVM 虚拟自动释放。

package com.example.threadlocal;

import java.util.Hashtable;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

public class ThreadLocalTest {
//    public  static Map<String,Object> data=new Hashtable<String,Object>();
    public static ThreadLocal<Object> threadLocal=new ThreadLocal<Object>();
    private static Random random=new Random();

    public static class Task implements Runnable{

        @Override
        public void run() {
            //在run方法中,随机生成一个变量(线程要关联的数据)。然后以当前线程名为key保存到map中
            int i = random.nextInt(1000);
            //获取当前线程名
            String name = Thread.currentThread().getName();
            System.out.println("线程【"+name+"】生成的随机数是:"+i);
//            data.put(name,i);
            threadLocal.set(i);
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
//            Object o = data.get(name);
            Object o = threadLocal.get();
            System.out.println("在线程【"+name+"】快结束时取出关联的数据是:"+o);
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            new Thread(new Task()).start();
        }
    }
}

JSON

json 是由键值对组成,并且由花括号(大括号)包围。每个键由引号引起来,键和值之间使用冒号进行分隔, 多组键值对之间进行逗号进行分隔

json的两个常用方法

json 的存在有两种形式。
一种是:对象的形式存在,我们叫它 json 对象。
一种是:字符串的形式存在,我们叫它 json 字符串。
一般我们要操作 json 中的数据的时候,需要 json 对象的格式。
一般我们要在客户端和服务器之间进行数据交换的时候,使用 json 字符串。
JSON.stringify() 把 json 对象转换成为 json 字符串
JSON.parse() 把 json 字符串转换成为 json 对象

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="pragma" content="no-cache" />
        <meta http-equiv="cache-control" content="no-cache" />
        <meta http-equiv="Expires" content="0" />
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Insert title here</title>
    </head>
    <body>
    <script type="text/javascript">
        // json的定义
        var jsonObj={
            "key1":12,
            "key2":"abc",
            "key3":true,
            "key4":[11,"arr",false],
            "key5":{ "key5_1" : 551, "key5_2" : "key5_2_value" },
            "key6":[{ "key6_1_1":6611, "key6_1_2":"key6_1_2_value"},
                {"key6_2_1":6621, "key6_2_2":"key6_2_2_value" }]
        };
        // json的访问
        alert(typeof(jsonObj));// object json 就是一个对象
        alert(jsonObj.key1); //12
        alert(jsonObj.key2); // abc
        alert(jsonObj.key3); // true
        alert(jsonObj.key4);// 得到数组[11,"arr",false] // json 中 数组值的遍历
        for(var i = 0; i < jsonObj.key4.length; i++) {
            alert(jsonObj.key4[i]);
        }
        alert(jsonObj.key5.key5_1);//551
        alert(jsonObj.key5.key5_2);//key5_2_value
        alert( jsonObj.key6 );// 得到 json 数组
        // 取出来每一个元素都是 json 对象
        var jsonItem = jsonObj.key6[0];
        alert( jsonItem.key6_1_1 ); //6611
        alert( jsonItem.key6_1_2 ); //key6_1_2_value
        // json对象转字符串
        // 把 json 对象转换成为 json 字符串
        var jsonObjString = JSON.stringify(jsonObj); // 特别像 Java 中对象的 toString
        alert(jsonObjString) // 把 json 字符串。转换成为 json 对象
        // json字符串转json对象
        var jsonObj2 = JSON.parse(jsonObjString);
        alert(jsonObj2.key1);// 12
    </script>
    </body>
</html>

json在java中的使用

package com.example.json;
import com.example.pojo.Person;
import com.google.gson.reflect.TypeToken;
import java.util.ArrayList;
public class PersonListType extends TypeToken<ArrayList<Person>> {
}
package com.example.json;

import com.example.pojo.Person;
import com.google.gson.reflect.TypeToken;

import java.util.HashMap;

public class PersonMapType extends TypeToken<HashMap<Integer, Person>> {
}
package com.example.json;

import com.example.pojo.Person;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.junit.Test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JsonTest {
    @Test //javaBean和json互转
    public void test1(){
        Person person=new Person(1,"lhd");
        //创建Gson对象实例
        Gson gson = new Gson();
        //toJson方法可以把java对象转换成为json字符串
        String personJsonString=gson.toJson(person);
        System.out.println(personJsonString);
        //fromJson把json字符串转换会java对象
        //第一个参数是json字符串,第二个参数是转换回去的Java对象类型
        Person person1 = gson.fromJson(personJsonString, Person.class);
        System.out.println(person1);
    }

    @Test //List和json互转
    public void test2(){
        List<Person> personList=new ArrayList<>();
        personList.add(new Person(1,"lhd"));
        personList.add(new Person(2,"lzy"));
        Gson gson = new Gson();
        // 把List集合转化为Json字符串
        String s = gson.toJson(personList);
        System.out.println(s);
//        List<Person> list = gson.fromJson(s, new PersonListType().getType());
        List<Person> list = gson.fromJson(s, new TypeToken<ArrayList<Person>>(){}.getType());
        System.out.println(list);
        Person person = list.get(0);
        System.out.println(person);

    }
    @Test //map和json互转
    public void test3(){
        Map<Integer, Person> personMap = new HashMap<>();
        personMap.put(1,new Person(1,"lhd"));
        personMap.put(2,new Person(2,"lzy"));
        Gson gson = new Gson();
        String s = gson.toJson(personMap);
        System.out.println(s);
//        Map<Integer, Person> personMap1 = gson.fromJson(s, new PersonMapType().getType());
//      也可以写成匿名内部类的形式
        Map<Integer, Person> personMap1 = gson.fromJson(s, new TypeToken<HashMap<Integer,Person>>(){}.getType());

        System.out.println(personMap1);
        Person person = personMap1.get(1);
        System.out.println(person);
    }
}

AJAX

什么是 AJAX 请求?
AJAX 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的
网页开发技术。 ajax 是一种浏览器异步发起请求。局部更新页面的技术。

javaScript 原生 Ajax 请求

原生的 Ajax 请求,
1、我们首先要创建 XMLHttpRequest对象
2、调用 open 方法设置请求参数
3、调用 send 方法发送请求
4、在 send 方法前绑定 onreadystatechange 事件,处理请求完成后的操作

方法 描述
open(method,url,async)
- method:请求的类型;GET 或 POST
- url:文件在服务器上的位置
- async:true(异步)或 false(同步)
send(string)
- string:仅用于 POST 请求

onreadystatechange 事件

当请求被发送到服务器时,我们需要执行一些基于响应的任务。
每当 readyState 改变时,就会触发 onreadystatechange 事件。
readyState 属性存有 XMLHttpRequest 的状态信息。
下面是 XMLHttpRequest 对象的三个重要的属性:

属性 描述
onreadystatechange 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
readyState 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
- 0: 请求未初始化
- 1: 服务器连接已建立
- 2: 请求已接收
- 3: 请求处理中
- 4: 请求已完成,且响应已就绪
status 200: “OK”
404: 未找到页面
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="pragma" content="no-cache" />
        <meta http-equiv="cache-control" content="no-cache" />
        <meta http-equiv="Expires" content="0" />
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Insert title here</title>
    </head>
    <body>
    <button onclick="ajaxRequest()">ajax request</button>
    <div id="div01">
    </div>
    <script type="text/javascript">
        // 在这里使用jacaScript语言发起Ajax请求,访问服务器AjaxServlet中javaScriptAjax
        function ajaxRequest() {
//             1、我们首先要创建XMLHttpRequest
            var xmlhttprequest =new XMLHttpRequest();
//             2、调用open方法设置请求参数
            xmlhttprequest.open("GET","http://localhost:8080/json_ajax_i18n/ajaxServlet?action=javaScriptAjax",true)
//             3、在send方法前绑定onreadystatechange事件,处理请求完成后的操作。
            xmlhttprequest.onreadystatechange=function () {
                if (xmlhttprequest.readyState==4&&xmlhttprequest.status==200){
                    // alert(xmlhttprequest.responseText)

                    //把相应的数据相应在页面(获取相应网址返回回来的数据)
                    var parse = JSON.parse(xmlhttprequest.responseText);
                    document.getElementById("div01").innerHTML= "编号"+parse.id+",姓名"+parse.name
                    //把相应的数据相应在页面
                    // document.getElementById("div01").innerHTML=xmlhttprequest.responseText
                }
            }
//             4、调用send方法发送请求
            xmlhttprequest.send()
        }
    </script>
    </body>
</html>
package com.example.json_ajax_i18n;

import com.example.pojo.Person;
import com.google.gson.Gson;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet(name = "AjaxServlet", value = "/ajaxServlet")
public class AjaxServlet extends BaseServlet {
    protected void javaScriptAjax(HttpServletRequest request,HttpServletResponse response)throws  ServletException,IOException{
        System.out.println("Ajax请求过来了");
        Person person = new Person(1, "lhd");

        //json格式的字符串
        Gson gson = new Gson();
        String s = gson.toJson(person);
        response.getWriter().write(s);
    }
}
package com.example.json_ajax_i18n;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public abstract class BaseServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 解决post乱码问题,设置请求的参数字符集为UTf-8
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
        // action参数就可以用来判断是当前用户模块的哪一个操作。
        String action = request.getParameter("action");
        // 定义一个Method方法对象
        Method actionMethod;
        try {
            // 通过反射获取到与action字符串对应的操作方法
            actionMethod = getClass().getDeclaredMethod(action, HttpServletRequest.class,
                    HttpServletResponse.class);
            // System.out.println(actionMethod);
            // 调用Method对象的invoke函数执行方法
            actionMethod.invoke(this, request, response);
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException e) {
            e.printStackTrace();
        }

    }

}

JQuery 的 Ajax 请求

$.ajax 方法
url 表示请求的地址
type 表示请求的类型 GET 或 POST 请求
data 表示发送给服务器的数据
格式有两种:
一:name=value&name=value
二:{key:value}
success 请求成功,响应的回调函数
dataType 响应的数据类型
常用的数据类型有:
text 表示纯文本
xml 表示 xml 数据
json 表示 json 对象
$.get 方法和$.post 方法
url 请求的 url 地址
data 发送的数据
callback 成功的回调函数
type 返回的数据类型
$.getJSON 方法
url 请求的 url 地址
data 发送给服务器的数据
callback 成功的回调函数
表单序列化 serialize()
serialize()可以把表单中所有表单项的内容都获取到,并以 name=value&name=value 的形式进行拼接。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="pragma" content="no-cache" />
        <meta http-equiv="cache-control" content="no-cache" />
        <meta http-equiv="Expires" content="0" />
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Insert title here</title>
        <script type="text/javascript" src="script/jquery-1.7.2.js"></script>
        <script type="text/javascript">
            $(function(){
                // ajax请求
                $("#ajaxBtn").click(function(){
                    $.ajax({
                        url:"http://localhost:8080/json_ajax_i18n/ajaxServlet",
                        data:"action=jQueryAjax",
                        type:"GET",
                        success:function (data) {
                            // alert("服务器返回的数据是"+data)
                            // var parse = JSON.parse(data);
                            $("#msg").html("编号"+data.id+",姓名"+data.name)

                        },
                        dataType:"json"
                    })
                    // alert("ajax btn");
                });

                // ajax--get请求
                $("#getBtn").click(function(){
                    $.get("http://localhost:8080/json_ajax_i18n/ajaxServlet","action=jQueryGet",function (data) {
                        $("#msg").html("GET编号"+data.id+",姓名"+data.name)
                    },"json");
                    // alert(" get btn ");

                });

                // ajax--post请求
                $("#postBtn").click(function(){
                    // post请求
                    $.post("http://localhost:8080/json_ajax_i18n/ajaxServlet","action=jQueryPost",function (data) {
                        $("#msg").html("POST编号"+data.id+",姓名"+data.name)
                    },"json");
                    // alert("post btn");

                });

                // ajax--getJson请求
                $("#getJSONBtn").click(function(){
                    // 调用
                    $.getJSON("http://localhost:8080/json_ajax_i18n/ajaxServlet","action=jQueryGetJSON",function (data) {
                        $("#msg").html("GetJSON编号"+data.id+",姓名"+data.name)
                    });
                    // alert("getJSON btn");

                });

                // ajax请求
                $("#submit").click(function(){
                    // 把参数序列化
                    // alert("serialize()");
                    alert($("#form01").serialize())
                    $.getJSON("http://localhost:8080/json_ajax_i18n/ajaxServlet"+$("#form01").serialize(),"action=jQuerySerialize&",function (data) {
                        $("#msg").html("jQuerySerialize编号"+data.id+",姓名"+data.name)
                    });
                });

            });
        </script>
    </head>
    <body>
    <div id="msg"></div>
        <div>
            <button id="ajaxBtn">$.ajax请求</button>
            <button id="getBtn">$.get请求</button>
            <button id="postBtn">$.post请求</button>
            <button id="getJSONBtn">$.getJSON请求</button>
        </div>
        <br/><br/>
        <form id="form01" >
            用户名:<input name="username" type="text" /><br/>
            密码:<input name="password" type="password" /><br/>
            下拉单选:<select name="single">
                  <option value="Single">Single</option>
                  <option value="Single2">Single2</option>
            </select><br/>
              下拉多选:
              <select name="multiple" multiple="multiple">
                <option selected="selected" value="Multiple">Multiple</option>
                <option value="Multiple2">Multiple2</option>
                <option selected="selected" value="Multiple3">Multiple3</option>
              </select><br/>
              复选:
             <input type="checkbox" name="check" value="check1"/> check1
             <input type="checkbox" name="check" value="check2" checked="checked"/> check2<br/>
             单选:
             <input type="radio" name="radio" value="radio1" checked="checked"/> radio1
             <input type="radio" name="radio" value="radio2"/> radio2<br/>
        </form>            
        <button id="submit">提交--serialize()</button>
    </body>
</html>
package com.example.json_ajax_i18n;

import com.example.pojo.Person;
import com.google.gson.Gson;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet(name = "AjaxServlet", value = "/ajaxServlet")
public class AjaxServlet extends BaseServlet {
    protected void javaScriptAjax(HttpServletRequest request,HttpServletResponse response)throws  ServletException,IOException{
        System.out.println("Ajax请求过来了");
        Person person = new Person(1, "lhd");

        //json格式的字符串
        Gson gson = new Gson();
        String s = gson.toJson(person);
        response.getWriter().write(s);
    }
    protected void jQueryAjax(HttpServletRequest request,HttpServletResponse response)throws  ServletException,IOException{
        System.out.println("jQuery请求过来了");
        Person person = new Person(1, "lhd");

        //json格式的字符串
        Gson gson = new Gson();
        String s = gson.toJson(person);
        response.getWriter().write(s);
    }
    protected void jQueryGet(HttpServletRequest request,HttpServletResponse response)throws  ServletException,IOException{
        System.out.println("jQueryGet请求过来了");
        Person person = new Person(1, "lhd");

        //json格式的字符串
        Gson gson = new Gson();
        String s = gson.toJson(person);
        response.getWriter().write(s);
    }
    protected void jQueryPost(HttpServletRequest request,HttpServletResponse response)throws  ServletException,IOException{
        System.out.println("jQueryPost请求过来了");
        Person person = new Person(1, "lhd");

        //json格式的字符串
        Gson gson = new Gson();
        String s = gson.toJson(person);
        response.getWriter().write(s);
    }
    protected void jQueryGetJSON(HttpServletRequest request,HttpServletResponse response)throws  ServletException,IOException{
        System.out.println("jQueryGetJSON请求过来了");
        Person person = new Person(1, "lhd");

        //json格式的字符串
        Gson gson = new Gson();
        String s = gson.toJson(person);
        response.getWriter().write(s);
    }
    protected void jQuerySerialize(HttpServletRequest request,HttpServletResponse response)throws  ServletException,IOException{
        System.out.println("jQuerySerialize请求过来了");
        System.out.println("用户名:"+request.getParameter("username"));
        System.out.println("密码:"+request.getParameter("password"));
        Person person = new Person(1, "lhd");

        //json格式的字符串
        Gson gson = new Gson();
        String s = gson.toJson(person);
        response.getWriter().write(s);
    }
}

i18n国际化

什么是 i18n 国际化?

  • 国际化(Internationalization)指的是同一个网站可以支持多种不同的语言,以方便不同国家,不同语种的用户访问。
  • 关于国际化我们想到的最简单的方案就是为不同的国家创建不同的网站,比如苹果公司,他的英文官网是: http://www.apple.com 而中国官网是 http://www.apple.com/cn
  • 苹果公司这种方案并不适合全部公司,而我们希望相同的一个网站,而不同人访问的时候可以根据用户所在的区域显示 不同的语言文字,而网站的布局样式等不发生改变。
  • 于是就有了我们说的国际化,国际化总的来说就是同一个网站不同国家的人来访问可以显示出不同的语言。但实际上这种需求并不强烈,一般真的有国际化需求的公司,主流采用的依然是苹果公司的那种方案,为不同的国家创建不同的页面。所以国际化的内容我们了解一下即可。
  • 国际化的英文 Internationalization,但是由于拼写过长,老外想了一个简单的写法叫做 I18N,代表的是 Internationalization 这个单词,以 I 开头,以 N 结尾,而中间是 18 个字母,所以简写为 I18N。以后我们说 I18N 和国际化是一个意思。

国家化资源properties测试

在resource目录下配置两个语言的配置文件
i18n_zh_CN.properties 中文

username=用户名
password=密码

i18n_en_US.properties 英文

username=username
password=password
package com.example.i18n;

import org.junit.Test;

import java.util.Locale;
import java.util.ResourceBundle;

public class I18nTest {
    @Test
    public void testLocale(){
        //获取你系统默认的语言,国家信息
        Locale locale = Locale.getDefault();
        System.out.println(locale);

        //遍历可用国家信息
        for (Locale availableLocale : Locale.getAvailableLocales()) {
            System.out.println(availableLocale);
        }

        //获取中文国家信息对象
        Locale china = Locale.CHINA;
        System.out.println(china);
        //获取英文国家信息对象
        System.out.println(Locale.US);
    }

    @Test
    public void testI18n(){
        Locale locale = Locale.US;//得到locale对象
        //通过指定的basename和Locale对象,读取相应的配置文件
        ResourceBundle bundle = ResourceBundle.getBundle("i18n", locale);
        System.out.println("用户名:"+bundle.getString("username"));
        System.out.println("密码:"+bundle.getString("password"));
    }
}