JavaWeb(JSP&Filter过滤器&CookieSession&JSONi18n&三层架构&文件上传下载&分页&对应JAR)

该笔记来自B站SGG-JavaWeb学习纪录,文章末贴出链接

2022.05.01

关于JavaBean

https://www.delftstack.com/zh/howto/java/java-bean/

关于数据库连接池

https://www.cnblogs.com/wenxuehai/p/15058811.html

关于读取配置文件

https://juejin.cn/post/6844904193489109006

关于java2mysql数据库驱动jdbc
因为我用的是Mysql 8.x,因此驱动包版本变化了( mysql-connector-java-8.0.16.jar)    
关于数据库配置文件
# 老版本:
username=root
password=root
url=jdbc:mysql://localhost:3306/book
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10

# 可能报错信息
# 1. Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. 
# 2. 时区异常
# 3. init datasource error, url: jdbc:mysql:/

# 新版本:
username=root
password=123456
url=jdbc:mysql://localhost:3306/book?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
# driverClassName=com.mysql.jdbc.Driver
driverClassName=com.mysql.cj.jdbc.Driver
initialSize=5
maxActive=10

# 参考链接https://blog.csdn.net/qq_26545503/article/details/104879286

2022.05.02

JavaEE项目三层架构

三层架构.png

     分层								包名										含义
1. web层/视图展现层                 com.xxx.web(.servlet/.controller)  
         
2. service层						com.xxx.service                                Service接口包
         					     com.xxx.service.impl					      Service接口实现类
         
3. dao持久层					   com.xxx.dao                                    Dao接口包
         						 com.xxx.dao.impl                               Dao接口实现类
         
4. 实体bean对象					   com.xxx.pojo(.entity/.domain/.bean)            JavaBean5. 测试包(单测)                    com.xxx.test(.junit)                            测试类,单测
         
6. 工具类					        com.xxx.utils                                  jdbc驱动连接
// 以注册业务为例 大致梳理下
1.  创建数据库表
    drop database if exists xxx;
	create database xxx;
	use xxx;
	create table t_xxx(
    	'id' int primary key auto_increment,
        'username' varchar(20) not null unique,
        'password' varchar(32) not null,
        'email' varchar(200)
    ) 

2. 编写数据库表对应的JavaBean对象 // 在pojo包下新建User类
     public class User{
         private Integer id;
         private String username;
         private String password;
         private String email;
         // 利用idea Generator自动生成getter/setter、toString、构造函数
         // ...
     }

3. 编写连接数据库jdbc工具类
    3.1 先导入需要的jar包(数据库和连接池)
    	druid-1.1.9.jar // 连接池
    	mysql-connector-java-8.0.16.jar // 数据库
    
    3.2 在源码src文件夹下新建jdbc.properties数据库属性配置文件
    	// 上面提到过
    
    3.3 在utils包下新建"JdbcUtils"工具类
    	// 读取jdbc.properties配置文件
    	// 创建数据库链接池
    
   	// 总的来说 jdbc这个工具类就是为了创建连接池跟mysql数据库进行连接和关闭连接
    
4. 编写"Dao"// 在上面那张图中 我们可以基本看到在Dao层其实就是作数据库的CURD
    4.1 先导入需要的jar包
    	commons-dbutils-1.3.jar // 对数据库操作的封装的jar包
    
    4.2 编写抽象类BaseDao // 目前我理解就是将可能会遇到的sql场景 利用DbUtils进行封装
    
    4.3 编写UserDao接口
    
    4.4 编写UserDao的实现UserDaoImpl // 继承至BaseDao实现UserDao
    
5. 编写"Service"// 从上面那张图中 我们可以看到在service层 主要是处理实际业务逻辑、调用dao层保存数据
    5.1 编写UserService接口
    
    5.2 编写UserService接口实现类 UserServiceImpl
    
6. 编写"web"// 从上面那张图中 看出web层就是接收客户端消息的第一层
    6.1 编写Servlet类 处理请求
Idea中Debug调试
1. 如何调试
    // 断点 + Debug启动服务器
    
2. 调试栏依次从左往右
    2.1 让代码往下执行一行
    2.2 可以进入当前方法体内(自己写的代码,非框架源码)
    2.3 强制进入当前方法体内
    2.4 跳出当前方法体外 
    2.5 
    2.6 停在光标所在行(相当于临时断点)
    
3. 变量窗口
    可以查看当前方法范围内所有有效的变量
    
4. 方法调用栈窗口
    方法调用栈可以查看当前线程有哪些方法调用信息;
    下面的调用上一行的方法。

2022.05.07

补充关于Dao层或Service层生成单元测试

quick-unitTest.png

2022.05.03

什么是jsp
jsp全称是java server pages Java的服务器页面
jsp的主要作用就是代替Servlet程序回传html页面的数据
jsp的访问
jsp页面和html页面一样,都是存放在web目录下,访问也跟访问html页面一样
jsp本质
jsp页面本质上是一个Servlet程序;
当第一次访问jsp页面时,Tomcat服务器会帮我们把jsp页面翻译成一个java源文件,并且还有个被编译为.class的字节码程序。
// 如a.jsp

jsp本质.png

打开源文件:
// a_jsp.java
public final class a_jsp extends org.apache.jasper.runtime.HttpJspBase{} 
// 其中HttpJspBase直接继承了HttpServlet类,本质上就是Servlet

// HttpJspBase.java
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage{}
jsp头部page指令相关
jsp的page指令可以修改jsp页面中的一些重要的属性,或者行为。
<%@ page
    language="java" // jsp翻译后是什么语言,暂时支持java
    
    contentType="text/html;charset=utf-8" // jsp返回的数据类型是什么,等同于resp.setContentType()参数值
    
    pageEncoding="utf-8" // 当前jsp页面文件本身的字符集
    
    import="java.utils.Map" // 等同于java中导包,导类
    
    // 以下两个属性是给out输出流使用
    autoFlush="true" // 设置当out输出流缓冲区满了后,是否自动刷新冲级区,默认true
    buffer="8kb" // 设置out缓冲区大小,默认8kb
    // 若设置autoFlush="false";buffer="1kb"则当jsp内容超过1kb时则报错显示 如:Java.io.IOException: Error JSP Buffer overflow
    
    errorPage="/errorPage.jsp" // 设置当jsp页面运行时出错,自动跳转去的错误页面路径
    // 路径一般以斜杠打头,表示请求地址为http://ip:port/工程路径/映射到代码的web目录下
    
    isErrorPage="false" // 设置当前jsp页面是否是错误信息页面,默认false,若是true则可以从源码中看到获取了一个Exception
    
    session="true" // 设置访问当前jsp页面,是否会创建HttpSession对象,默认true
    
    extends="" // 设置jsp翻译出来的java类默认继承谁
%>
jsp中的声明脚本
声明脚本格式:<%! 声明java代码 %>
作用:可以给jsp翻译出来的java类定义属性、方法、静态代码块、内部类
// 属性
    <%!
    	private String username;
		private String password;
    %>
// 方法
    <%!
        public int test(){
        	return 123;
        }
    %>
// 静态代码块
    <%!
        static {
        	System.out.println("static")
    	}
    %>
// 内部类
    <%!
        public static class A{
            private String email = "1@qq.com";
        }
    %>
jsp中的表达式脚本
表达式脚本格式:<%= 表达式 %>
作用:给jsp页面上输出数据

// 输出整型
    <%=
    	33
    %>
// 输出字符串
    <%=
    	"i am string"
    %>
...
 
特点:
    所有表达式脚本会被翻译到_jspService()方法中;
    所有表达式脚本会被翻译成out.print()输出到页面上;
    可以使用_jspService()方法中的所有对象,如:<%= request.getParameter("test") %>;
    所有表达式脚本不能以分号结束 
jsp中的代码脚本
代码脚本格式:<% java语句 %>
作用:在jsp页面中,编写自己需要的功能(java语法)
    
特点:
    翻译之后都在_jspService方法中;
    _jspService()方法中的对象都可以直接使用;
    可以由多个代码脚本块组合完成一个完整的java语句;
    可以和表达式脚本一起组合使用,在jsp页面上输出数据。
jsp九大内置对象及四大域对象
// 从编译后的源码中可以看出
request   // 请求对象
response  // 响应对象
pageContext  // jsp的上下文对象
session   // 会话对象
application  // ServletContext对象
config    // ServletConfig对象
out       // jsp输出流对象
page      // 指向当前jsp的对象
exception // 异常对象
    
// 4大域对象                     所属类                        scope范围
pageContext                (PageContextImpl)            当前jsp页面范围内有效
request                    (HttpServletRequest)         一次请求内有效
session                    (HttpSession)         一个会话范围(打开浏览器直到关闭)
application                (ServletContext)  整个web工程范围内(直到web工程停止)
    
以上4者可以像Map一样存取数据setAttribute(key,value)&getAttribute(key); 但存取范围有限及优先顺序,从下到大如下排列:
    pageContext -> request -> session -> application
jsp中out输出和response.getWriter.write()输出区别及out.write()和out.print()区别
首先:
    out也可以再jsp编译后的源码中看见,均使用out进行输出;
    reponse响应对象中,也可以设置返回给客户端的输出内容。
区别:
    两者均会先输出到各自对应的缓冲区,比如out缓冲区,response缓冲区;
    当jsp页面所有代码执行完成后会做两个操作:
    	1. 执行out.flush()操作,会把out缓冲区中的数据追加写入到reponse缓冲区末尾
    	2. 执行response刷新操作,把response缓冲区所有数据写回到客户端。
    因此,默认情况下两者均存在时,会先输出reponse内容再输出out内容(除非手动的执行out.flush()方法),即在jsp页面时均使用"out"来统一输出。
    
其中:
    out.write() 输出字符串没问题,但输出整型,会输出Ascal码(底层代码 cb[nextChar++] = (char) c 做了char类型的强制类型转换)
    out.print() 输出任意类型没问题(底层代码均做了所有类型转换为字符串后再调用out.write()方法输出)
因此:
    在jsp页面中,统一使用out.print()来进行输出。
jsp常用标签
1. 静态包含
    <%@ include file="" %>

2. 动态包含
	<jsp:include page="">
	  <jsp:param name="test" value="test" />
    </jsp:include>

	区别:
		2.1 使用动态包含时也会把动态部分编译为java代码和字节码
		2.2 JspRuntimeLibrary.include(request, response, "/include/footer.jsp", out, false); 底层是使用这样的方法去动态加载,并把父页面的request\response\out对象传递给了子页面,因此父子共用一个out输出流
		2.3 可以传递参数,如上所示,在子页面使用request.getParameter(key)获取

3. 转发标签
	<jsp:forward page=""></jsp:forward>
三大组件之二:Listener监听器
1. JavaWeb三大组件
    1.1 Servlet程序
    1.2 Filter过滤器
    1.3 Listener监听器
    
2. 什么是监听器
    它是JavaEE的规范,就是接口

3. 作用
    监听某种事物变化,然后通过回调函数让程序做一些相应的处理
    
4. ServletContextListner监听器
    4.1 监听ServletContext对象的创建和销毁
    4.2 涉及实现的两个方法
    	contextInitialized()方法: web工程启动时候回调
    	contextDestroyed()方法: web工程停止的时候回调
    
5. 如何使用
    5.1 编写一个类去实现ServletContextListener接口
    5.2 实现其两个回调方法
    5.3 在web.xml中配置监听器
    	<listener>
        	<listener-class>classpath</listener-class>
    	</listener>

2022.05.04

EL表达式
1. 含义
    Express Language(表达式语言)
2. 作用
    主要是代替jsp页面中的表达式脚本在jsp页面中进行数据的输出
3. 格式
    ${ 表达式 }
EL表达式获取域数据的顺序
pageContext.setAttribute("key","pageContext");
request.setAttribute("key","request");
session.setAttribute("key","session");
application.setAttribute("key","application");
当四个域中都有相同的key的数据时,EL表达式会按照四个域的从小到大的顺序,找到就输出
    ${ key } // pageContext
EL中的".“点运算和”[]"中括号运算
.点运算,可以输出Bean对象中某个属性的值 pojo.username // 其中特别注意在EL中.点操作符后面默认找的是其getXxx() 如上面就是找的getUsername() getter方法,因此在EL中使用时注意可以不要get前缀,直接后面的内容
[]中括号运算,可以输出有序集合中某个元素的值 pojo.cities[0]
也可以输出map集合中key含特殊字符的值 pojo.map['x+x+x'] || pojo.map["y.y.y"]
EL中11个隐含对象
// 该11个隐含对象是EL自定义的,因此只能在El表达式中使用,注意与jsp9大内置对象区别

变量                         类型					 作用
// 注意在jsp内置对象中也有pageContext是当前jsp上下文对象 这里是在EL中使用来获取jsp9大对象    
pageContext             PageContextImpl          获取jsp中九大内置对象
    
1. 协议
    jsp: <% request.getScheme() %>
    EL: ${ pageContext.request.scheme }
2. 服务器IP
    jsp: <% request.getServerName() %>
    EL: ${ pageContext.request.serverName }
3. 服务器端口
    jsp: <% request.getServerPort() %>
    EL: ${ pageContext.request.serverPort }
4. 工程路径
    jsp: <% request.getContextPath() %>
    EL: ${ pageContext.request.contextPath }
5. 请求方法
    jsp: <% request.getMethod() %>
    EL: ${ pageContext.request.method }
6. 客户端IP
    jsp: <% request.getRemoteHost() %>
    EL: ${ pageContext.request.remoteHost }
7. 会话id
    jsp: <% session.getId() %>
    EL: ${ pageContext.session.id }

// 这四个对标jsp中的4大域对象    
pageScope               Map<String,Object>       获取pageContext域中数据
requestScope            Map<String,Object>       获取request域中数据
sessionScope            Map<String,Object>       获取session域中数据applicationScope        Map<String,Object>       获取ServletContext域中数据
    
param                   Map<String,String>       获取请求参数的值
paramValues             Map<String,String[]>     获取多个值的参数值

header                  Map<String,String>       获取请求头的信息
headerValues            Map<String,String[]>     获取多个值的请求头值
    
cookie                  Map<String,Cookie>       获取当前请求的Cookie信息

// 这里需要注意,我们在servlet配置web.xml时 使用<init-param>来配置的"servletConfig"值 而这里的initParam对标的是我们在servlet配置web.xml中<context-param>这个"servletContext"值
initParam               Map<String,String>       获取web.xml中配置的<context-param>上下文参数
    
cookie                  Map<String,Cookie>       获取当前请求的Cookie信息

// 这里需要注意,我们在servlet配置web.xml时 使用<init-param>来配置的"servletConfig"值 而这里的initParam对标的是我们在servlet配置web.xml中<context-param>这个"servletContext"值
initParam               Map<String,String>       获取web.xml中配置的<context-param>上下文参数

2022.05.05

文件下载-Servlet版
1. 基于Apache的commons.io包
    
2. 步骤
    1.1 获取指定文件的MIME类型
    1.2 设置响应头告诉客户端(浏览器)Content-Type为MIME
    // 这步是否编写的基础在于若想要浏览器下载 则需要设置,若不需要下载 比如图片可以只返回流直接打开,若是excel,word等则需要设置
    1.3 设置响应头中内容处理Content-Disposition 其中
    	attachment表示"附件"
    	filename表示"附件名称"
    		其中在文件名称这里需要注意若是中文,则浏览器响应头中会出现乱码,因此需要对中文名称进行编码
    		// ie/chrome(URLEncoder解决)
    			URLEncoder.encode("中文下载名称.xls", StandardCharsets.UTF_8))
    		// firefox(需要以base64编码及固定格式解决)
    			"=?utf-8?B?"
+ new BASE64Encoder().encode("中文下载名称.xls".getBytes("utf-8")) + "?=";
             =?charset?B?xxxxx?= 现在我们对这段内容进行一下说明。
    		=? 表示编码内容的开始
    		charset 表示字符集
    		B 表示 BASE64 编码
    		xxxx 表示文件名 BASE64 编码后的内容
    		?= 表示编码内容的结束
                 
    1.4 指定文件输入流读入
    1.5 输入流赋值给输出流
                 
3. 源码
    // 1. 获取要下载的文件名及文件磁盘路径
        String downloadFileName = "中文下载名称.xls";
        String downloadFilePath = "/WEB-INF/upload/" + downloadFileName;

	// 2. 获取文件Mime及设置响应头
ServletContext servletContext = getServletContext();
	// 2.1 获取要下载的文件类型 (通过servletContext读取)
String mimeType = servletContext.getMimeType(downloadFilePath);
	// 2.2 需要设置响应头中的Content-Type告诉客户端返回的数据类型
resp.setContentType(mimeType + "charset=utf-8");
	// 2.3 设置内容描述:这步比较重要:就是为了区分到底是"直接浏览器打开显示" 还是说需要下载
	// 若是下载则需要设置Content-Disposition,其中attachment表示"附件"的意思,后面跟filename"文件名称"
resp.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(downloadFileName, StandardCharsets.UTF_8));

	// 3. 读取文件输入流
InputStream resourceAsStream = servletContext.getResourceAsStream(downloadFilePath);
ServletOutputStream outputStream = resp.getOutputStream(); // 输出流
	// 使用Apache上传jar包中的方法来复制输入流到输出流
IOUtils.copy(resourceAsStream, outputStream);

2022.05.09

lib包
1. Tomcat
    Edit Configurations -> 导入本地tomcat目录下的所有lib包进来 -> 这样再new 文件的时候就可以看见Servlet

导入tomcat所有lib包配置tomcat.png

2. Servlet
    servlet-api.jar


3. 单元测试
    junit-4.12.jar
    hamcrest-core-1.3.jar

4. xml解析
    dom4j-1.6.1.jar    

5. JSP
    jsp-api.jar // from tomcat


6. EL表达式
    el-api.jar // from tomcat


7. JSTL
    taglibs-standard-impl-1.2.1.jar
    taglibs-standard-spec-1.2.1.jar
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


8. MySQL
    mysql-connector-java-8.0.16.jar


9. JDBC连接池
    // 主要使用来读取数据库配置文件使用连接池进行连接
    druid-1.1.9.jar // utils工具类使用


10.Map对象转换为Bean对象
    commons-beanutils-1.8.0.jar // utils工具类使用
    commons-logging-1.1.1.jar // 依赖

11. MySQL执行sql
    commons-dbutils-1.3.jar // dao层使用

12. 文件上传下载
    commons-fileupload-1.2.1.jar
    commons-io-1.4.jar //     IOUtils.copy()下载
    
13. 谷歌验证码库
    kaptcha-2.3.2.jar
    
14. JSON
    gson-2.2.4.jar
分页参数
pageNo   当前页码
    当前页码由客户端进行传递

pageSize  每页显示数量
    每页显示数量由两种因素决定
        1. 客户端进行传递
        2. 由页面布局决定

pageCountTotal 总记录数
    可由sql语句求出
    select count(*) from 表名

pageNoTotal  总页码
    由总记录数 / 每页数量求出
    若总记录数%每页数量>0,则总页码+1
    
items  当前页数据
    可由sql求出
    select* from 表名 limit begin,pageSize;
    begin公式:(pageNo - 1) * pageSize
将部分异常抛出给Tomcat配置跳转指定页面
<!--error-page 标签配置,服务器出错之后,自动跳转的页面-->
<error-page>
    <!--error-code 是错误类型-->
    <error-code>500</error-code>
    <!--location 标签表示。要跳转去的页面路径-->
    <location>/pages/error/error500.jsp</location>
</error-page>
<!--error-page 标签配置,服务器出错之后,自动跳转的页面-->
<error-page>
    <!--error-code 是错误类型-->
    <error-code>404</error-code>
    <!--location 标签表示。要跳转去的页面路径-->
    <location>/pages/error/error404.jsp</location>
</error-page>

但是需要注意 在某些地方捕获了异常 最后层次必须要抛出异常通知Tomcat,这样配置才会生效
Cookie
1. 什么是Cookie
       服务器端通知客户端保存键值对的一种技术;
       客户端有了Cookie后,每次请求都发送给服务器端;
       每个Cookie大小不超过4kb

2. 服务端如何创建Cookie并通知客户端(Servlet版本)
       Cookie cookie = new Cookie("keyTest","valueTest");
       resp.addCookie(cookie); 
       // 实际通过http响应头Set-Cookie:keyTest=valueTest 告知客户端(浏览器)创建
 
3. 服务端如何获取Cookie(Servlet版本)
       客户端http请求头中包含了Cookie信息;
       Cookie[] cookies = req.getCookies() // Cookie[]
       for(Cookie cookie : cookies){
            // cookie.getName() 获取key
            // cookie.getValue() 获取value
       }

4. 服务端如何修改Cookie(Servlet版本)
        4.1 // 创建一个需要修改的同名key的cookie对象
            Cookie editCookie = new Cookie("key","value");
            // 设置响应头
            resp.addCookie(cookie);
        
        4.2 // 先找到需要修改的Cookie对象
            // 使用Cookie对象的setValue()方法
            cookie.setValue("editValue");
            // 设置响应头
            resp.addCookie(cookie);

5. Cookie生命控制
        主要使用cookie对象的setMaxAge()方法
        正数:表示在指定的秒数后过期
        负数:表示浏览器一关,Cookie 就会被删除(默认值是-10:表示马上删除 Cookie
        
6. Cookie的path属性过滤
        Cookie 的 path 属性可以有效的过滤哪些 Cookie 可以发送给服务器。哪些不发
        path 属性是通过请求的地址来进行有效的过滤
        // cookie1 path=/工程路径
        // cookie2 path=/工程路径/test
        
        若此时访问路径为http://ip:port/工程路径
        此时在浏览器的cookie中只会看见cookie1,而看不见cookie2,同样请求也只会带cookie1,不会带cookie2
        若此时访问路径为http://ip:port/工程路径/test/xxx.html
        此时浏览器中同时看到cookie1,cookie2,同样请求也会同时带上
        
        Cookie cookie2 = new Cookie("path","path");
        cookie2.setPath(req.getContextPath + "/test");
        resp.addCookie(cookie2);
Session
1. 什么是Session
    是一个接口(HttpSession;
    是一个会话,它是用来维护一个客户端和服务器之间关联的一种技术;
    每个客户端都有自己的一个Session会话;

2. 服务端如何创建或获取Session
        // 创建和获取是同一个方法
        HttpSession session = req.getSession()
        // 通过isNew()方法来判断是否是第一次创建
        Boolean isNew  = session.isNew();
	   // 每个会话都有一个身份证号。也就是 ID 值。而且这个 ID 是唯一的。
	    String id = session.getId();

3. session生命控制
    3.1 Session默认的超时时长在我们的服务器(Tomcat)的配置文件web.xml中配置的,表示当前tomcat服务器下所有的session超时时长是30分钟
    	<session-config>
    		<session-timeout>30</session-timeout>
    	</session-config>
    
    3.2 若想当前Tomcat服务器下的某个web工程,设置其session时长,则需要在自己工程下的web.xml中更改配置
    	<session-config>
    		<session-timeout>20</session-timeout>
    	</session-config>
    
    3.3 若想指定修改个别Session超时时长,则需要使用HttpSession提供的3个方法
    	session.setMaxInactiveInterval() // 以秒为单位,值为正数时,到点销毁,值为负数时,表示永不销毁
    	session.getMaxInactiveInterval() // 获取当前session的超时时长
    	session.invalidate() // 让当前session会话立马超时无效
    
    3.4 Session超时概念
    	它是指,客户端两次请求的最大间隔时长
    

 4. session技术,底层是基于Cookie技术来实现的 

浏览器与session.png

什么是Filter过滤器
1. Filter过滤器是JavaWeb三大组件之一,三大组件分别是:Servlet程序、Listener监听器、Filter过滤器
2. 是一个JavaEE的规范接口,过滤器是执行过滤任务的对象,这些任务是针对对某一资源(servlet 或静态内容)的请求或来自某一资源的响应执行的,抑或同时针对这两者执行。
3. 它的作用:拦截请求、过滤响应
4. 常见的应用场景:
    	权限检查、日志操作、事务管理...
如何创建Filter过滤器
1. 编写一个类去实现Filter接口
2. 实现其过滤方法doFilter()
    // 这里注意下doFilter()方法中的参数 需要强制类型转换为HttpServletRequest
    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
    HttpSession session = httpServletRequest.getSession();

    Object user = session.getAttribute("user");
    if (user == null) {
        System.out.println("无权限");
    } else {
        // 继续执行(必须执行该方法 不然没效果)
        filterChain.doFilter(servletRequest, servletResponse);
    }

3. web.xml配置Filter拦截路径
    <!--    配置Filter过滤器 大致和Servlet相同 -->
    <filter>
        <!--Filter过滤器起一个别名-->
        <filter-name>AdminFilter</filter-name>
        <!--        Filter类全类名路径-->
        <filter-class>com.atguigu.filter.AdminFilter</filter-class>
    </filter>
    <!--    配置filter拦截路径-->
    <filter-mapping>
        <!--        拦截哪一个Filter名称-->
        <filter-name>AdminFilter</filter-name>
        <!--        指定拦截路径:斜杠表示http://ip:port/工程路径/ 其映射到idea的web目录下 admin目录下的全部-->
        <url-pattern>/admin/*</url-pattern>
    </filter-mapping>

Filter流程.png

Filter生命周期
1. 执行构造器方法
2. 执行init初始化方法
	// 1、2步是在web工程启动的时候执行(Filter已经创建)
3. doFilter()方法
    // 每次拦截到请求,会执行
4. destroy方法
    // 在web工程停止的时候调用
FilterConfig类
1. Filter过滤器的配置文件类
2. Tomcat每次创建Filter的时候,同时创建了一个FilterConfig3. 作用
    	获取Filter的名称 web.xml中filter-name配置项
    	获取Filter配置的参数 web.xml中 init-param参数 // 同servletConfig
    	获取ServletContext对象
    
// web.xml
    <filter>
    	<init-param>
    		<param-name>username</param-name>
    		<param-value>root</param-value>
    	</init-param>
    </filter>
FilterChain过滤器链
针对同一个路径进行多次过滤器调用

Filterchain.png

Filter拦截路径方式
1. 精准匹配
	<url-pattern>/xxx.jsp</url-pattern>
 	// http:ip:port/工程路径/xxx.jsp
2. 目录匹配
    <url-pattern>/admin/*</url-pattern>
    // http:ip:port/工程路径/admin/*
3. 后缀名匹配    
    <url-pattern>*.html</url-pattern>
    <url-pattern>*.png</url-pattern>
    
Filter过滤器只关心请求地址是否匹配,不关心请求资源是否存在    
ThreadLocal
1. ThreadLocal它可以给当前线程关联一个数据(可以是普通变量、对象、数组、集合)
2. 作用:解决多线程的数据安全问题
3. 特点:
    3.1 ThreadLocal可以为当前线程关联一个数据(它可以像Map一样存取数据,key为当前线程)
    3.2 每一个ThreadLocal对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个ThreadLocal对象实例
    3.3 每个ThreadLocal对象实例定义的时候,一般都是static类型
    3.4 ThreadLocal中保存数据,在线程销毁后,会由JVM虚拟自动释放

public class ThreadLocalTest {
    public static ThreadLocal<Object> threadLocal = new ThreadLocal<>();

    private static final 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);
            // 将随机数放入到当前threadLocal实例中
            threadLocal.set(i);

            // 休眠3秒
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            // 在 Run 方法结束之前,以当前线程名获取出数据并打印。查看是否可以取出操作
            Object o = threadLocal.get();
            System.out.println("在线程[" + name + "]快结束时取出关联的数据是:" + o);
        }
    }

    public static void main(String[] args) {
        // 通过for循环创建三个新线程
        for (int i = 0; i < 3; i++) {
            new Thread(new Task()).start();
        }
    }
}    
ThreadLocal如何配合JDBC开启数据库事务

jdbc&ThreadLocal开启事务.png

/**
* 获取数据库连接池中的连接
* @return 如果返回 null,说明获取连接失败<br/>有值就是获取连接成功
*/
public static Connection getConnection(){
    Connection conn = conns.get();
    if (conn == null) {
        try {
            conn = dataSource.getConnection();//从数据库连接池中获取连接
            conns.set(conn); // 保存到 ThreadLocal 对象中,供后面的 jdbc 操作使用
            conn.setAutoCommit(false); // 设置为手动管理事务
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    return conn;
}
/**
* 提交事务,并关闭释放连接
*/
public static void commitAndClose(){
    Connection connection = conns.get();
    if (connection != null) { // 如果不等于 null,说明 之前使用过连接,操作过数据库
        try {
            connection.commit(); // 提交 事务
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                connection.close(); // 关闭连接,资源资源
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    // 一定要执行 remove 操作,否则就会出错。(因为 Tomcat 服务器底层使用了线程池技术)
    conns.remove();
}
/**
* 回滚事务,并关闭释放连接
*/
public static void rollbackAndClose(){
    Connection connection = conns.get();
    if (connection != null) { // 如果不等于 null,说明 之前使用过连接,操作过数据库
        try {
            connection.rollback();//回滚事务
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                connection.close(); // 关闭连接,资源资源
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    // 一定要执行 remove 操作,否则就会出错。(因为 Tomcat 服务器底层使用了线程池技术)
    conns.remove();
}
需要注意的是我们要在dao层如果捕获到异常 要抛出来 throw new RuntimeException(e) 到上层的service层,如果在service层作commit()或者rollback()操作,岂不是所有的service我们都要去try/catch,因此如下如何用Filter配合处理统一作提交或者回滚事务
    
再次需要注意 若嵌套多层 需要再每一层往外层抛出异常 最后Filter才好捕获!
Filter如何统一try/catch service层作所有servlet操作事务

Filter统一操作.png

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain
                     filterChain) throws IOException, ServletException {
    try {
        filterChain.doFilter(servletRequest,servletResponse);
        JdbcUtils.commitAndClose();// 提交事务
    } catch (Exception e) {
        JdbcUtils.rollbackAndClose();//回滚事务
        e.printStackTrace();
    }
}
将部分异常抛出给Tomcat配置跳转指定页面
<!--error-page 标签配置,服务器出错之后,自动跳转的页面-->
<error-page>
    <!--error-code 是错误类型-->
    <error-code>500</error-code>
    <!--location 标签表示。要跳转去的页面路径-->
    <location>/pages/error/error500.jsp</location>
</error-page>
<!--error-page 标签配置,服务器出错之后,自动跳转的页面-->
<error-page>
    <!--error-code 是错误类型-->
    <error-code>404</error-code>
    <!--location 标签表示。要跳转去的页面路径-->
    <location>/pages/error/error404.jsp</location>
</error-page>

但是需要注意 在某些地方捕获了异常 最后层次必须要抛出异常通知Tomcat,这样配置才会生效

2022.05.11

JSON
1. 
json 是一种轻量级的数据交换格式。
轻量级指的是跟 xml 做比较。
数据交换指的是客户端和服务器之间业务数据的传递格式。
    
2. 定义
    json 是由键值对组成,并且由花括号(大括号)包围。每个键由引号引起来,键和值之间使用冒号进行分隔,多组键值对之间进行逗号进行分隔。
    
3. 访问
    json 本身是一个对象。
	json 中的 key 我们可以理解为是对象中的一个属性。
	json 中的 key 访问就跟访问对象的属性一样: json 对象.key
 
4. 两个常用方法
    json 的存在有两种形式。
    一种是:对象的形式存在,我们叫它 json 对象。
    一种是:字符串的形式存在,我们叫它 json 字符串。
    一般我们要操作 json 中的数据的时候,需要 json 对象的格式。
    一般我们要在客户端和服务器之间进行数据交换的时候,使用 json 字符串。
    JSON.stringify() 把 json 对象转换成为 json 字符串
    JSON.parse() 把 json 字符串转换成为 json 对象
    
5. 常用转换 (使用Gson依赖包)
    5.1 Json2Bean & Bean2Json
   	    JsonBeanTest jsonBeanTest = new JsonBeanTest(1, "javabean2Json");
        Gson gson = new Gson();
        // 转换为JSON字符串
        String s = gson.toJson(jsonBeanTest);
        System.out.println("bean2JSONString: " + s);

        // JSON字符串转换为bean对象
        JsonBeanTest json2bean = gson.fromJson(s, jsonBeanTest.getClass()); // 参数2是Class Type 针对JavaBean使用
        System.out.println("JSONString2bean: " + json2bean); 
   
	5.2 Json2List & List2Json
        // 1. 创建List对象
        List<JsonBeanTest> beanList = new ArrayList<>();
        beanList.add(new JsonBeanTest(1, "root"));
        beanList.add(new JsonBeanTest(2, "admin"));

        Gson gson = new Gson();

        // 2. 转为JSON字符串
        String s = gson.toJson(beanList);
        System.out.println("list2JsonString: " + s);

        // 3. JSON转List
        List<JsonBeanTest> beanList2 = gson.fromJson(s, new TypeToken<ArrayList<JsonBeanTest>>() {
        }.getType()); // 匿名内部类
        System.out.println("JsonString2List: " + beanList2);
        System.out.println("ListOneOf: " + beanList2.get(1));
	
	5.3 Json2Map & Map2Json
        // 1. 创建Map对象
        Map<String, JsonBeanTest> stringObjectHashMap = new HashMap<>();
        stringObjectHashMap.put("1", new JsonBeanTest(1, "li"));
        stringObjectHashMap.put("2", new JsonBeanTest(2, "da"));
        stringObjectHashMap.put("3", new JsonBeanTest(3, "ye"));

        Gson gson = new Gson();
        // map2json
        String s = gson.toJson(stringObjectHashMap);
        System.out.println("map2json: " + s);

        // json2map
        Map<String, Object> o = gson.fromJson(s, new
                TypeToken<HashMap<Integer, JsonBeanTest>>() {
                }.getType()); // 匿名内部类
        System.out.println("json2map: " + o);
        System.out.println(o.get(1));
i18n

i18n.png

SGGJavaWeb

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值