JavaWeb笔记小结

文章目录


第一章 Tomcat 基础

一、 web 概念

1. 软件架构

  1. C/S: 客户端/服务器端
  2. B/S: 浏览器/服务器端

2.资源分类

  1. 静态资源: 所有用户访问后,得到的结果都是一样的,称为静态资源。静态资源可以直接被浏览器解析。如图片、视频。
  2. 动态资源: 每个用户访问相同资源后,得到的结果可能不一样 , 称为动态资源。动态资源被访问后,需要先转换为静态资源返回给浏览器通过浏览器进行解析。如:servlet,jsp,php,asp…

二、常见的web服务器

1、 概念

  1. 服务器:安装了服务器软件的计算机
  2. 服务器软件:接收用户的请求,处理请求,做出响应
  3. web服务器软件:接收用户的请求,处理请求,做出响应。

在web服务器软件中,可以部署web项目,让用户通过浏览器来访问这些项目

2、常见服务器软件

动态服务器:

  • webLogic:oracle公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
  • webSphere:IBM公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
  • JBOSS:JBOSS公司的,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。
  • Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范servlet/jsp。开源的,免费的。(300左右的并发)

静态的服务器:

  • nginx(代理,反向代理等)极高的并发
  • apache

3、Tomcat 历史

1) Tomcat 最初由Sun公司的软件架构师 James Duncan Davidson 开发,名称为 “JavaWebServer”。
2) 1999年 ,在 Davidson 的帮助下,该项目于1999年于apache 软件基金会旗下的 JServ 项目合并,并发布第一个版本(3.x), 即是现在的Tomcat,该版本实现了Servlet2.2 和 JSP 1.1 规范 。
3) 2001年,Tomcat 发布了4.0版本, 作为里程碑式的版本,Tomcat 完全重新设计了其架构,并实现了 Servlet 2.3 和 JSP1.2规范。

目前企业中的Tomcat服务器, 主流版本还是 7.x 和 8.x 。

4、 Tomcat 安装

下载地址

在这里插入图片描述

5、Tomcat 目录结构

目录目录下文件说明
bin/存放Tomcat的启动、停止等批处理脚本文件
startup.bat ,startup.sh用于在windows和linux下的启动脚本
shutdown.bat ,shutdown.sh用于在windows和linux下的停止脚本
conf/用于存放Tomcat的相关配置文件
Catalina用于存储针对每个虚拟机的Context配置
context.xml用于定义所有web应用均需加载的Context配置,如果web应用指定了自己的context.xml ,该文件将被覆盖
catalina.propertiesTomcat 的环境变量配置
catalina.policyTomcat 运行的安全策略配置
logging.propertiesTomcat 的日志配置文件, 可以通过该文件修改Tomcat 的日志级别及日志路径等
server.xmlTomcat 服务器的核心配置文件
tomcat-users.xml定义Tomcat默认的用户及角色映射信息配置
web.xmlTomcat 中所有应用默认的部署描述文件, 主要定义了基础Servlet和MIME映射。
lib/Tomcat 服务器的依赖包
logs/Tomcat 默认的日志存放目录
webapps/Tomcat 默认的Web应用部署目录
work/Web 应用JSP代码生成和编译的临时目录

6、Tomcat 启动停止

双击 bin/startup.bat 文件 启动
双击 bin/shutdown.bat 文件 停止
访问:http://localhost:8080

三、Tomcat 架构

1、HTTP工作原理

HTTP协议是浏览器与服务器之间的数据传送协议。作为应用层协议,HTTP是基于TCP/IP协议来传递数据的(HTML文件、图片、查询结果等),HTTP协议不涉及数据包(Packet)传输,主要规定了客户端和服务器之间的通信格式
在这里插入图片描述

2、HTTP服务器请求处理

浏览器发给服务端的是一个HTTP格式的请求,HTTP服务器收到这个请求后,需要调用服务端程序来处理,所谓的服务端程序就是你写的Java类,一般来说不同的请求需要由不同的Java类来处理
在这里插入图片描述
图1 , 表示HTTP服务器直接调用具体业务类,它们是紧耦合的

图2,HTTP服务器不直接调用业务类,而是把请求交给容器来处理容器通过Servlet接口调用业务类。因此Servlet接口和Servlet容器的出现,达到了HTTP服务器与业务类解耦的目的。而Servlet接口和Servlet容器这一整套规范叫作Servlet规范。Tomcat按照Servlet规范的要求实现了Servlet容器,同时它们也具有HTTP服务器的功能。作为Java程序员,如果我们要实现新的业务功能,只需要实现一个Servlet,并把它注册到Tomcat(Servlet容器)中,剩下的事情就由Tomcat帮我们处理了。

3、Servlet容器工作流程

当客户请求某个资源时,HTTP服务器会用一个ServletRequest对象把客户的请求信息封装起来,然后调用Servlet容器的service方法Servlet容器拿到请求后,根据请求的URL和Servlet的映射关系,找到相应的Servlet,如果Servlet还没有被加载,就用反射机制创建这个Servlet,并调用Servlet的init方法来完成初始化,接着调用Servlet的service方法来处理请求,把ServletResponse对象返回给HTTP服务器,HTTP服务器会把响应发送给客户端。
在这里插入图片描述

4、Tomcat整体架构

我们现在知道了Tomcat要实现两个核心功能:

1) 处理Socket连接,负责网络字节流与Request和Response对象的转化。
2) 加载和管理Servlet,以及具体处理Request请求。

因此Tomcat设计了两个核心组件连接器(Connector)和容器(Container)来分别做这两件事情。连接器负责对外交流,容器负责内部处理。

大致图解为:
在这里插入图片描述

四、Tomcat 服务器配置

Tomcat 服务器的配置主要集中于 tomcat/conf 下的 catalina.policy、catalina.properties、context.xml、server.xml、tomcat-users.xml、web.xml 文件。

server.xml

server.xml 是tomcat 服务器的核心配置文件,包含了Tomcat的 Servlet 容器(Catalina)的所有配置。


Server:
Server是server.xml的根元素,用于创建一个Server实例,默认使用的实现类是org.apache.catalina.core.StandardServer

<Server port="8005" shutdown="SHUTDOWN">
...
</Server>

属性说明:
port : Tomcat 监听的关闭服务器的端口。
shutdown: 关闭服务器的指令字符串。


Connector:
Connector 用于创建链接器实例。默认情况下,server.xml 配置了两个链接器,一个支持HTTP协议,一个支持AJP协议。因此大多数情况下,我们并不需要新增链接器配置,只是根据需要对已有链接器进
行优化。

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000"
redirectPort="8443" />

属性说明:
1) port: 端口号,Connector 用于创建服务端Socket 并进行监听, 以等待客户端请求链接。如果该属性设置为0,Tomcat将会随机选择一个可用的端口号给当前Connector 使用。
2) protocol : 当前Connector 支持的访问协议。 默认为 HTTP/1.1
3) connectionTimeOut : Connector 接收链接后的等待超时时间, 单位为毫秒。 -1 表示不超时
4) URIEncoding : 用于指定编码URI的字符编码, Tomcat8.x版本默认的编码为 UTF-8

五、手写Tomcat

六、创建Javaweb项目

1、创建项目

在这里插入图片描述
在这里插入图片描述

2、项目结构

在这里插入图片描述

3、配置Tomcat

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

七、WebSocket

1、WebSocket与HTTP


HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。

这种通信模型有一个弊端:HTTP 协议无法实现服务器主动向客户端发起消息。

这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。大多数 Web 应用程序将通过频繁的异步 JavaScript 和 XML(AJAX)请求实现长轮询。轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。


WebSocket 连接允许客户端和服务器之间进行全双工通信,以便任一方都可以通过建立的连接将数据推送到另一端。WebSocket 只需要建立一次连接,就可以一直保持连接状态。这相比于轮询方式的不停建立连接显然效率要大大提高。

状态码:101


在这里插入图片描述

2、特点

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)没有同源限制,客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

示例:

ws://example.com:80/some/path

在这里插入图片描述

3、Tomcat的WebSocket

Tomcat自7.0.5版本开始支持WebSocket,并且实现了Java WebSocket规范(JSR356 ),而在7.0.5版本之前(7.0.2版本之后)则采用自定义API,即WebSocketServlet。

根据JSR356的规定,Java WebSocket应用由一系列的WebSocket Endpoint组成。Endpoint是一个Java对象,代表WebSocket链接的一端,对于服务端,我们可以视为处理具体WebSocket消息的接口,就像Servlet之于HTTP请求一样(不同之处在于Endpoint每个链接一个实例)。

3.1 定义Endpoint:
  1. 第一种是编程式,即继承类javax.websocket.Endpoint并实现其方法。
  2. 第二种是注解式,即定义一个POJO对象,为其添加Endpoint相关的注解。

Endpoint实例在WebSocket握手时创建,并在客户端与服务端链接过程中有效,最后在链接关闭时结束。Endpoint接口明确定义了与其生命周期相关的方法,规范实现者确保在生命周期的各个阶段调用实例的相关方法。

3.2 Endpoint:
3.2.1 生命周期:
  1. onOpen:当开启一个新的会话时调用。这是客户端与服务器握手成功后调用的方法。等同于注解@OnOpen。
  2. onClose:当会话关闭时调用。等同于注解@OnClose。
  3. onError:当链接过程中异常时调用。等同于注解@OnError。

当客户端链接到一个Endpoint时,服务器端会为其创建一个唯一的会话(javax.websocket.Session)。会话在WebSocket握手之后创建,并在链接关闭时结束。当生命周期中触发各个事件时,都会将当前会话传给Endpoint。

3.2.2 接受、发送消息:
  1. 接受消息:
    我们通过为Session添加MessageHandler消息处理器来接收消息。当采用注解方式定义Endpoint时,我们还可以通过 @OnMessage 指定接收消息的方法。

  2. 发送消息:
    发送消息则由RemoteEndpoint完成,其实例由Session维护,根据使用情况,我们可以通过Session.getBasicRemote获取同步消息发送的实例或者通过Session.getAsyncRemote获取异步消息发送的实例。

WebSocket通过javax.websocket.WebSocketContainer接口维护应用中定义的所有Endpoint。它在每个Web应用中只有一个实例,类似于传统Web应用中的ServletContext。

最后,WebSocket规范提供了一个接口javax.websocket.server.ServerApplicationConfig,通过它,我们可以为编程式的Endpoint创建配置(如指定请求地址),还可以过滤只有符合条件的Endpoint提供服务。该接口的实现同样通过SCI机制加载。

第二章 Servlet入门

servlet就是一个java程序,用来处理请求和响应。

一、Servlet架构

在这里插入图片描述

二、Servlet任务

处理请求equest,生成响应response

三、Servlet相关知识

1、Servlet加载时机

在默认情况下,当Web客户第一次请求访问某个Servlet时,Web容器会创建这个Servlet的实例。当设置了web.xml中的子元素后,Servlet容器在启动Web应用时,将按照指定顺序创建并初始化这个Servlet。设置的数值大于0即可。

<servlet>
  <servlet-name>HelloServlet</servlet-name>
  <servlet-class>com.langsin.servlet.HelloServlet</servlet-class>
  <load-on-startup>2</load-on-startup>
</servlet>

2、Servlet的生命周期

  • init():Servlet进行初始化
  • service():Servlet处理客户端的请求
  • destroy():Servlet结束,释放资源

在调用destroy()方法后,Servlet由JVM的垃圾回首器进行垃圾回收


init()方法:

Servlet被装载后,Servlet容器创建一个Servlet实例并且调用Servlet的init()方法进行初始化在Servlet生命周期中init()方法只被调用一次
当用户调用一个Servlet时,Servlet容器就会创建一个Servlet实例,每一个用户请求都会产生一个新的线程,init()方法简单的创建或加载一些数据,这些数据将会被用在Servlet的整个生命周期。


service()方法:

service()方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service()方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。
每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service()方法检查HTTP 请求类型(GET、POST(增加)、PUT(修改)、DELETE 等),并在适当的时候调用doGet()、doPost()等方法。


destroy()方法:

destroy()方法只会被调用一次,在Servlet生命周期结束时被调用。destroy()方法可以让Servlet关闭数据库连接、停止后台、把cookie列表或点击计数器写入到磁盘,并执行其他类似的清理活动。
在调用destroy()方法之后,Servlet对象被标记为垃圾回收。

总结:

  • 在首次访问某个Servlet时,init()方法会被执行,而且也会执行service()方法。
  • 再次访问时,只会执行service()方法,不再执行init()方法。
  • 在关闭Web容器时会调用destroy()方法。

3、实现一个servlet

当服务器接收到一个请求,就要有一个servlet去处理这个请求,所以完成一个servlet通常需要两步走。

  1. 写一个java程序定义一个servlet
  2. 配置一下servlet确定这个servlet要处理哪一个请求
1、创建Servlet的三种方式

(1)实现javax.servlet.Servlet接口。
(2)继承javax.servlet.GenericServlet类
(3)继承javax.servlet.http.HttpServlet类(常用)

2、配置Servlet的两种方式

(1)使用web.xml文件配置Servlet

<servlet>
  <servlet-name>user</servlet-name>
  <servlet-class>com.controller.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>user</servlet-name>
  <url-pattern>/user.do</url-pattern>
</servlet-mapping>

(2)使用注解进行Servlet配置

@WebServlet("/user.do")

四、servlet的匹配规则

1、四种匹配规则

(1) 精确匹配

<url-pattern>中配置的项必须与url完全精确匹配。

<servlet-mapping>
  <servlet-name>user</servlet-name>
  <url-pattern>/user.do</url-pattern>
</servlet-mapping>

(2) 路径匹配

以“/”字符开头,并以“/*”结尾的字符串用于路径匹配

<servlet-mapping>
  <servlet-name>user</servlet-name>
  <url-pattern>/user/*</url-pattern>
</servlet-mapping>
路径以/user/开始,后面的路径可以任意。

(3)扩展名匹配**

以“*.”开头的字符串被用于扩展名匹配

<servlet-mapping>
  <servlet-name>user</servlet-name>
  <url-pattern>*.jsp</url-pattern>
  <url-pattern>*.do</url-pattern>
</servlet-mapping>
任何扩展名为jsp或action的url请求都会匹配

(4) 缺省匹配

<servlet-mapping>
  <servlet-name>user</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

2、匹配顺序

  1. 精确匹配。
  2. 路径匹配,先最长路径匹配,再最短路径匹配。
  3. 扩展名匹配。
    注意:使用扩展名匹配,前面就不能有任何的路径。
  4. 缺省匹配,以上都找不到servlet,就用默认的servlet

3、注意问题

路径匹配和扩展名匹配无法同时设置

<url-pattern>/user/*.action</url-pattern>是非法的

<url-pattern>/aa/*/bb</url-pattern>是精确匹配,合法,这里的*不是通配的含义

"/*“和”/"含义并不相同

“/*”属于路径匹配,并且可以匹配所有request
由于路径匹配的优先级仅次于精确匹配,
所以“/*”会覆盖所有的扩展名匹配,很多404错误均由此引起,
所以这是一种特别恶劣的匹配模式。

“/”是servlet中特殊的匹配模式,
切该模式有且仅有一个实例,优先级最低,
不会覆盖其他任何url-pattern,只是会替换servlet容器的内建default servlet ,
该模式同样会匹配所有request。

“/*”和“/”均会拦截静态资源的加载

五、请求和响应

1、请求-request

(1)request概述

request是Servlet.service()方法的一个参数,类型为javax.servlet.http.HttpServletRequest。在客户端发出每个请求时,服务器都会创建一个request对象,并把请求数据封装到request中,然后在调用Servlet.service()方法时传递给service()方法,这说明在service()方法中可以通过request对象来获取请求数据。

request的功能:

  • 封装了请求头数据
  • 封装了请求正文数据,如果是GET请求,那么就没有正文
  • request是一个域对象,可以把它当成Map来添加获取数据
  • request提供了请求转发和请求包含功能
(2)request获取请求头数据

相关方法:

  • String getHeader(String name):获取指定名称的请求头
  • Enumeration getHeaderNames():获取所有请求头名称
  • int getIntHeader(String name):获取值为int类型的请求头
(3)request获取请求相关的其它方法
  • int getContentLength():获取请求体的字节数,GET请求没有请求体,没有请求体返回-1;
  • String getContentType():获取请求类型,如果请求是GET,那么这个方法返回null;如果是POST请求,那么默认为application/x-www-form-urlencoded,表示请求体内容使用了URL编码;
  • String getMethod():返回请求方法,例如:GET
  • Locale getLocale():返回当前客户端浏览器的Locale。java.util.Locale表示国家和言语,这个东西在国际化中很有用;
  • String getCharacterEncoding():获取请求编码,如果没有setCharacterEncoding(),那么返回null,表示使用ISO-8859-1编码;
  • void setCharacterEncoding(String code):设置请求编码,只对请求体有效!注意,对于GET而言,没有请求体!!! 所以此方法只能对POST请求中的参数有效!
  • String getContextPath():返回上下文路径,例如:/hello
  • String getQueryString():返回请求URL中的参数,例如:name=zhangSan
  • String getRequestURI():返回请求URI路径,例如:/hello/oneServlet
  • StringBuffer getRequestURL():返回请求URL路径,例如:http://localhost/hello/oneServlet,即返回除了参数以外的路径信息;
  • String getServletPath():返回Servlet路径,例如:/oneServlet
  • String getRemoteAddr():返回当前客户端的IP地址;
  • String getRemoteHost():返回当前客户端的主机名,但这个方法的实现还是获取IP地址;
  • String getScheme():返回请求协议,例如:http;
  • String getServerName():返回主机名,例如:localhost
  • int getServerPort():返回服务器端口号,例如:8080

案例:request.getRemoteAddr():封IP

String ip = request.getRemoteAddr();   
if("127.0.0.1".equals(ip)) {   
	response. getWriter().print("您的IP已被禁止!");   
} else {   
   response.getWriter().print("Hello!");   
} 
(4)request获取请求参数
  • 浏览器地址栏直接输入:一定是GET请求;
  • 超链接:一定是GET请求;
  • 表单:可以是GET,也可以是POST,这取决与的method属性值;

GET请求和POST请求的区别:

GET请求:
Ø 请求参数会在浏览器的地址栏中显示,所以不安全
Ø 请求参数长度限制长度在1K之内;
Ø GET请求没有请求体,无法通过request.setCharacterEncoding()来设置参数的编码;

POST请求:
Ø 请求参数不会显示浏览器的地址栏,相对安全;
Ø 请求参数长度没有限制;


使用request获取请求参数的API:

  • String getParameter(String name):通过指定名称获取参数值;
  • String[] getParameterValues(String name):当多个参数名称相同时,可以使用方法来获取;
  • Enumeration getParameterNames():获取所有参数的名字;
  • Map<String,String[]> getParameterMap():获取所有参数封装到Map中,其中key为参数名,value为参数值,因为一个参数名称可能有多个值,所以参数值是String[],而不是String。
(5)请求转发
public class AServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
	System.out.println("AServlet");
	request.getRequestDispatcher("/BServlet").forward(request, response);
	}
}
(6)request域方法

一个请求会创建一个request对象,如果在一个请求中经历了多个Servlet,那么多个Servlet就可以使用request来共享数据.

  • void setAttribute(String name, Object value):用来存储一个对象,也可以称之为存储一个域属性
  • Object getAttribute(String name):用来获取request中的数据,当前在获取之前需要先去存储才行,例如:String value =
    (String)request.getAttribute(“xxx”);,获取名为xxx的域属性;
  • void removeAttribute(String name):用来移除request中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;
  • Enumeration getAttributeNames():获取所有域属性的名称;

2、响应-response

(1) response概述

response是Servlet.service方法的一个参数,类型为javax.servlet.http.HttpServletResponse。
在客户端发出每个请求时,服务器都会创建一个response对象,并传入给Servlet.service()方法。
response对象是用来对客户端进行响应的,这说明在service()方法中使用response对象可以完成对客户端的响应工作。

response对象的功能:

  • 设置响应头信息
  • 发送状态码
  • 设置响应正文
  • 重定向
(2)response响应正文

response是响应对象,向客户端输出响应正文(响应体)可以使用response的响应流,repsonse一共提供了两个响应流对象:

  • PrintWriter out = response.getWriter():获取字符流,处理字符;
  • ServletOutputStream out = response.getOutputStream():获取字节流,处理文件;

注意,在一个请求中,不能同时使用这两个流!也就是说,要么你使用repsonse.getWriter(),要么使用response.getOutputStream(),但不能同时使用这两个流。不然会抛出IllegalStateException异常。

字符响应流:

(1)字符编码

重要:在使用response.getWriter()时需要注意默认字符编码为ISO-8859-1,如果希望设置字符流的字符编码为utf-8,可以使用response.setCharaceterEncoding(“utf-8”) 来设置。这样可以保证输出给客户端的字符都是使用UTF-8编码的!
但客户端浏览器并不知道响应数据是什么编码的!如果希望通知客户端使用UTF-8来解读响应数据,那么还是使用response.setContentType(“text/html;charset=utf-8”) 方法比较好,
因为这个方法不只会调用response.setCharaceterEncoding(“utf-8”),还会设置content-type响应头,客户端浏览器会使用content-type头来解读响应数据。

(2)缓冲区

response.getWriter()是PrintWriter类型,所以它有缓冲区,缓冲区的默认大小为8KB。也就是说,在响应数据没有输出8KB之前,数据都是存放在缓冲区中,而不会立刻发送到客户端。当Servlet执行结束后,服务器才会去刷新流,使缓冲区中的数据发送到客户端。
如果希望响应数据马上发送给客户端:
Ø 向流中写入大于8KB的数据;
Ø 调用response.flushBuffer()方法来手动刷新缓冲区;

(3)设置响应头信息

使用response对象的setHeader()方法来设置响应头!使用该方法设置的响应头最终会发送给客户端浏览器!

  • response.setHeader(“content-type”, “text/html;charset=utf-8”)

    设置content-type响应头,该头的作用是告诉浏览器响应内容为html类型,编码为utf-8。而且同时会设置response的字符流编码为utf-8,即response.setCharaceterEncoding(“utf-8”);

  • response.setHeader(“Refresh”,“5;URL=http://www.baidu.cn”)
    5秒后自动跳转到百度主页

(4)设置状态码及其他方法
  • response.setContentType(“text/html;charset=utf-8”):等同与调用
  • response.setHeader(“content-type”, “text/html;charset=utf-8”);用它就行了。
  • response.setCharacterEncoding(“utf-8”):设置字符响应流的字符编码为utf-8;
  • response.setStatus(200):设置状态码;
  • response.sendError(404,“您要查找的资源不存在”):当发送错误状态码时,Tomcat会跳转到固定的错误页面去,但可以显示错误信息。
(5)重定向

响应码为200表示响应成功,而响应码为302表示重定向。

public class AServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setStatus(302);
		response.setHeader("Location", "http://www.baidu.com");
	} 
}
public class AServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.sendRedirect("http://www.baidu.com");
	}
}

重定向与转发的区别:

转发过程: 客户端浏览器发送http请求 → web服务器接受此请求 → 调用内部的一个方法在容器内部完成请求处理和转发动作 → 将目标资源发送给客户。

//java代码示例
request.getRequestDispatcher("xxx.jsp或者servlet").forward(request,response);

重定向过程: 客户端浏览器发送http请求 → web服务器接收后发送30X状态码响应及对应新的location给客户浏览器 → 客户浏览器发现是30X响应,则自动再发送一个新的http请求,请求url是新的location地址→ 服务器根据此请求寻找资源并发送给客户。

//java代码示例
response.sendRedirect("xxx.jsp或者servlet");

转发和重定向对比:

转发重定向
跳转方式服务器端转发客户端转发
客户端发送请求次数1次2次
客户端地址栏是否改变不变
是否共享request域共享不共享(request域中的数据丢失),必须使用session传递属性
是否共享response域共享不共享
范围网站内可以跨站点
JSPURL不可带参数URL可带参数
是否隐藏路径隐藏不隐藏

什么时候使用重定向,什么时候使用转发?

原则上: 要保持request域的数据时使用转发,要访问外站资源的时候用重定向,其余随便;
特殊的应用: 对数据进行修改、删除、添加操作的时候,应该用response.sendRedirect()。如果是采用了request.getRequestDispatcher().forward(request,response),那么操作前后的地址栏都不会发生改变,仍然是修改的控制器,如果此时再对当前页面刷新的话,就会重新发送一次请求对数据进行修改,这也就是有的人在刷新一次页面就增加一条数据的原因。

转发与重定向的安全性:

  • 转发安全性: 在服务器内部实现跳转,客户端不知道跳转路径,相对来说比较安全。
  • 重定向安全性: 客户端参与到跳转流程,给攻击者带来了攻击入口,受威胁的可能性较大。
    比如一个HTTP参数包含URL,Web应用程序将请求重定向到这个URL,攻击者可以通过修改这个参数,引导用户到恶意站点,并且通过将恶意域名进行十六进制编码,一般用户很难识别这是什么样的URL;或者指引到该网站的管理员界面,如果访问控制没有做好将导致一般用户可以直接进入管理界面。
  • 重定向和转发检查列表:
    重定向之前,验证重定向的目标URL。
    使用白名单验证重定向目标。 如果在网站内重定向,可以使用相对路径URL。
    重定向或者转发之前,要验证用户是否有权限访问目标URL。

3、sesion和cookie

http是无状态的,他不保存状态,意思就是一个浏览器发的请求,随后就断开了,下一次发送请求就和上一次无关了。
比如一个用户购买一个商品,第一次需要登录,如果再买一个时向服务器发送请求,服务器如果不知道是谁发的,那么他就得再登录一次,这显然是不合理的,于是就提出了cookie和session的概念。
cookie是记录在浏览器端的一个字符串,session是保存在服务器端的一个对象。他们两互相配合让服务器有了能识别客户端一些状态的能力,意思就是服务就就能知道这个客户端有没有登录等。cookie就相当于通行证session就是门房,进去时需要从门房识别一个身份

粗略的描述一下过程:

  1. 当浏览器向客户端发送请求时,服务器会为他创建一个session,同时相应会加一个头(SetCookie: jsessionid=ewrwerwer123)
  2. 浏览器得到相应就会在在自己这保存下这个字符串,以后访问这个网站的时候就会一直带着。
  3. 当下一个请求发起时,会带着这个cookie的信息,服务器通过查询id找的session,通过session内保存的信息,就能获得这个客户端的状态。

第三章 jsp入门

一、JSP基础语法

1、JSP模板元素

JSP页面中的HTML内容称之为JSP模版元素。
JSP模版元素定义了网页的基本骨架,即定义了页面的结构和外观。

2、JSP脚本片段

JSP脚本片断用于在JSP页面中编写多行Java代码(在<%%>不能定义方法)。
语法:<%多行java代码%>

注意:

  1. JSP脚本片断中只能出现java代码,不能出现其它模板元素, JSP引擎在翻译JSP页面中,会将JSP脚本片断中的Java代码将被原封不动地放到Servlet的_jspService方法中。
  2. JSP脚本片断中的Java代码必须严格遵循Java语法,例如,每执行语句后面必须用分号(;)结束。
  3. 在一个JSP页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文本、HTML标记和其
    他JSP元素。
  4. 多个脚本片断中的代码可以相互访问

3、JSP注释

注释类型使用
显式注释HTML风格的注释:<!- - 注释内容- ->
隐式注释JAVA风格的注释://、/……/
JSP自己的注释<%- - 注释内容- -%>

注意:
HTML的注释在浏览器中查看源文件的时候是可以看得到的,而JAVA注释和JSP注释在浏览器中查看源文件时是看不到注释的内容的。

二、JSP原理

1、JSP的本质

浏览器向服务器发请求,不管访问的是什么资源,其实都是在访问Servlet,所以当访问一个jsp页面时,其实也是在访问一个Servlet,服务器在执行jsp的时候,首先把jsp编译成一个Servlet,所以我们访问jsp时,其实不是在访问jsp,而是在访问jsp翻译过后的那个Servlet。
jsp的本质其实就是个html模板,编译器会根据模板生成对应的servlet

2、_jspService方法

问题1:Jsp页面中的html排版标签是如何被发送到客户端的?
浏览器接收到的这些数据,都是在_jspService方法中输出给浏览器的。

public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response) throws java.io.IOException, javax.servlet.ServletException {
	final javax.servlet.jsp.PageContext pageContext;
	javax.servlet.http.HttpSession session = null;
	final javax.servlet.ServletContext application;
	final javax.servlet.ServletConfig config;
	javax.servlet.jsp.JspWriter out = null;
	final java.lang.Object page = this;
	javax.servlet.jsp.JspWriter _jspx_out = null;
	javax.servlet.jsp.PageContext _jspx_page_context = null;
	try {
		response.setContentType("text/html; charset=UTF-8");
		pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true);
		_jspx_page_context = pageContext;
		application = pageContext.getServletContext();
		config = pageContext.getServletConfig();
		session = pageContext.getSession();
		out = pageContext.getOut();
		_jspx_out = out;
		out.write("\r\n");
		out.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n");
		out.write("<html>\r\n");
		out.write("<head>\r\n");
		out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
		out.write("<title>Insert title here</title>\r\n");
		out.write("</head>\r\n");
		out.write("<body>\r\n");
		out.write("\t");
		out.write('\r');
		out.write('\n');
		out.write(' ');
		TestFun();
		out.println("name:" + name);
		out.write("\r\n");
		out.write("</body>\r\n");
		out.write("</html>");
	} catch (java.lang.Throwable t) {
		if (!(t instanceof javax.servlet.jsp.SkipPageException)){
			out = _jspx_out;
			if (out != null && out.getBufferSize() != 0)
			try {
				if (response.isCommitted()) {
					out.flush();
				} else {
					out.clearBuffer();
				}
			} catch (java.io.IOException e) {}
			if (_jspx_page_context != null)
				_jspx_page_context.handlePageException(t);
			else throw new ServletException(t);
		}
	} finally {
		_jspxFactory.releasePageContext(_jspx_page_context);
	}
}

问题2:Jsp页面中的java代码服务器是如何执行的?
在jsp中编写的java代码会被翻译到jspService方法中去,当执行jspService方法处理请求时,就会执行在jsp编写的java代码了,所以Jsp页面中的java代码服务器是通过调用_jspService方法处理请求时执行的。

3、jsp在服务器的执行流程

第一次执行:

  1. 客户端通过电脑连接服务器,因为是请求是动态的,所以所有的请求交给WEB容器来处理
  2. 在容器中找到需要执行的*.jsp文件
  3. 之后*.jsp文件通过转换变为*.java文件
  4. .java文件经过编译后,形成.class文件
  5. 最终服务器要执行形成的*.class文件

第二次执行:

  1. 因为已经存在了*.class文件,所以不在需要转换和编译的过程
    修改后执行:
  2. 源文件已经被修改过了,所以需要重新转换,重新编译。

三、JSP指令

1、JSP指令标识的语法格式

<%@ 指令名 属性1 = "属性1的值" 属性2 = "属性2的值" ....%>
  • 指令名:用于指定指令名称 在JSP中包含page include raglib 这3种指令
  • 属性: 用于指定指令属性名称 不同的指令包含不同的属性 在同一个指令中可以设置多个属性 各个属性之间用逗号或者空格隔开
  • 属性值:用于指定属性的值

2、Page指令

定义整个JSP页面的相关属性

语法格式:

<%@ page 属性1 = "属性1的值" 属性2 = "属性2的值" ....%>

language属性
用于设置整个JSP页面的使用的语言,目前只支持JAVA语言,改属性默认值是JAVA

<%@ page language="java" %>

improt属性
设置JSP导入的类包

<%@ page improt="java.util.*" %>

pageEccoding属性
这种JSP页面的编码格式,也就是指定文件编码
设置JSP页面的MIME类型和字符编码

<%@ page contentType ="text/html;charset=UTF-8" %>

Sesssions属性
设置页面是否使用HTTP的session会话对象.Boolen类型,默认值是true
JSP模板

<%@ page session ="false" %>

注意:session是JSP的内置对象之一
autoFlush属性
设置JSP页面缓存满时,是否自动刷新缓存,默认值是:true, 如果这种为false,则当页面缓存满是就会抛出异常

<%@ page autoFlush ="false" %>

isErrorPage属性
把当前页面设置成错误处理页面来处理另外jsp页面的错误

<%@ page isErrorPage ="true" %>

errorPage属性
指定当前jsp页面异常错误的另一个JSP页面,指定的JSP页面的isErrorPage属性必须为true,属性值是一个url字符串

<%@ page errorPage ="errorPage.jsp" %>

3、include指令

include指令用于引入其它JSP页面,如果使用include指令引入了其它JSP页面,那么JSP引擎将把这两个JSP翻译成一个servlet。所以include指令引入通常也称之为静态引入

语法格式:

<%@ include file="relativeURL"%>

file属性用于指定被引入文件的路径。路径以"/"开头,表示代表当前web应用。

注意:

  1. 被引入的文件必须遵循JSP语法
  2. 被引入的文件可以使用任意的扩展名,即使其扩展名是html,JSP引擎也会按照处理jsp页面的方式
    处理它里面的内容,为了见明知意,JSP规范建议使用.jspf(JSP fragments(片段))作为静态引入文件的扩展名。
  3. 由于使用include指令将会涉及到2个JSP页面,并会把2个JSP翻译成一个servlet,所以这2个JSP页面的指令不能冲突(除了pageEncoding和导包除外)。

四、JSP标签

一、 Jsp标签分类

1)内置标签(动作标签): 不需要在jsp页面导入标签
2)jstl标签: 需要在jsp页面中导入标签
3)自定义标签 : 开发者自行定义,需要在jsp页面导入标签

JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护。

常用内置标签:

1、标签一<jsp:include>
2、标签<jsp:forward>和<jsp:param>
<jsp:forward>标签用于把给另外一个资源(服务器跳转,地址不变)。

<%--使用jsp:forward标签进行请求转发--%>
<jsp:forward page="/index2.jsp" >
<jsp:param value="10086" name="num"/>
<jsp:param value="10010" name="num2"/>
</jsp:forward>

五、九大内置对象

对象名描述类型作用域
request请求对象javax.servlet.ServletRequestRequest
response响应对象javax.servlet.SrvletResponsePage
pageContext页面上下文对象javax.servlet.jsp.PageContextPage
session会话对象javax.servlet.http.HttpSessionSession
application应用程序对象javax.servlet.ServletContextApplication
out输出对象javax.servlet.jsp.JspWriterPage
config配置对象javax.servlet.ServletConfigPage
page页面对象javax.lang.ObjectPage
exception例外对象javax.lang.ThrowablePage

六、JSP属性作用域

  1. 当前页(pageContext):一个属性只能在一个页面中取得,跳转到其他页面无法取得
  2. 一次服务器请求(request):一个页面中设置的属性,只要经过了请求重定向之后的页面可以继续取得。
  3. 一次会话(session):一个用户设置的内容,只要是与此用户相关的页面都可以访问(一个会话表示一个人,这个人设置的东西只要这个人不走,就依然有效),关了浏览器就不见了。
  4. 上下文中(application):在整个服务器上设置的属性,所有人都可以访问

七、静态资源的路径问题

模板:

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
	<head>
		<base href="<%=basePath%>">
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title>title</title>
	</head>
	<body>
		这是模板
	</body>
</html>

八、错误页面、404页面、欢迎页

模板:

<error-page>
	<error-code>404</error-code>
	<location>/pages/404.jsp</location>
</error-page>

<error-page>
	<exception-type>java.lang.Exception</exception-type>
	<location>/pages/err.jsp</location>
</error-page>

<welcome-file-list>
	<welcome-file>/pages/home.jsp</welcome-file>
</welcome-file-list>

第四章 EL表达式和JSTL标签库

一、EL表达式

1、特点

(1)是一个由java开发的工具包
(2)用于从特定域对象中读取并写入到响应体开发任务,不能向域对象中写入。
(3)EL工具包自动存在Tomcat的lib中(el-api.jar),开发是可以直接使用,无需其他额外的包。
(4)标准格式 : ${域对象别名.。关键字} 到指定的域中获取相应关键字的内容,并将其写入到响应体。

2、域对象

jspel描述
applicationapplicationScope全局作用域对象
sessionsessionScope会话作用域
requestrequestScope请求作用域对象
pageContextpageScope当前页作用域对象

默认查找顺序: pageScope -> requestScope -> sessionScope -> applicationScope

案例:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
	<title>jsp</title>
</head>
<body>
	<%
		application.setAttribute("name","application");
		session.setAttribute("name","session");
		request.setAttribute("name","request");
		pageContext.setAttribute("name","pageContext");
	%>
	<br>--------------------使用java语言---------------------------<br>
		application中的值:<%= application.getAttribute("name") %> <br>
		session中的值:<%= session.getAttribute("name") %> <br>
		request中的值:<%= request.getAttribute("name") %> <br>
		pageContext中的值:<%= pageContext.getAttribute("name") %> <br>
	<br>--------------------使用EL表达式---------------------------<br>
		application中的值:${applicationScope.name} <br>
		session中的值:${sessionScope.name} <br>
		request中的值:${requestScope.name} <br>
		pageContext中的值:${pageScope.name} <br>
	<br>----------------使用EL表达式,省略域对象---------------------<br>
		application中的值:${name} <br>
</body>
</html>

3、支持的运算

(1)数学运算
(2)比较运算 > gt < lt >= ge <= le == eq != !=
(3)逻辑预算 && || !

4、其他的内置对象

(1)param 使用 ${param.请求参数名} 从请求参数中获取参数内容
(2)paramValues 使用 ${ paramValues.请求参数名 } 从请求参数中获取多个值,以数组的形式
(3)initParam 使用 ${ initParam.参数名 } 获取初始化参数

5、EL表达式的缺陷

(1)只能读取域对象中的值,不能写入
(2)不支持if判断和控制语句

二、JSTL标签工具类

1、基本介绍

(1) JSP Standrad Tag Lib jsp标准标签库
(2) sun公司提供
(3)组成

  • 核心标签 对java在jsp上基本功能进行封装,如 if while等
  • sql标签 JDBC在jsp上的使用
  • xml标签 Dom4j在jsp上的使用
  • format标签 jsp文件格式转换

2、使用方式

(1)导入依赖的jar包 jstl.jar standard.jar
(2)在jsp中引入JSTL的core包依赖约束

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

3、重要标签的使用

(1) <c:set>

<c:set scope="request" var="name" value="zhangsan" />

(2)<c:if >

<c:set scope="page" var="age" value="20"/>
<c:if test="${ age ge 18 }">

ge 大于等于 le 小于等于 gt大于 lt 小于

(3)<c:choose>

<c:choose>
	<c:when test="${age eq 18}"></c:when>
	<c:otherwise></c:otherwise>
</c:choose>

(4)<c:forEach>

<c:forEach var="申明循环变量的名称" begin="初始化循环变量" end="循环变量可以接受的最大值" step="循环变量的递增或递减值">
*** step属性可以不写,默认递增1
*** 循环变量默认保存在pageContext中
</c:forEach>

第五章 Listener、Filter

一、概念

  • servlet

servlet是一种运行服务器端的java应用程序,他可以用来处理请求和响应

  • filter

过滤器,不像Servlet,它不能产生一个请求或者响应,它是一个中间者,能修改处理经过他的请求和响应,并不能直接给客户端响应。

  • listener

监听器,他用来监听容器内的一些变化,如session的创建,销毁等。当变化产生时,监听器就要完成一些工作。

二、生命周期

1、servlet:

servlet的生命周期始于它被装入web服务器的内存时,并在web服务器终止或重新装入servlet时结束。servlet一旦被装入web服务器,一般不会从web服务器内存中删除,直至web服务器关闭或重新结束。

  1. 装入:启动服务器时加载Servlet的实例;
  2. 初始化:web服务器启动时或web服务器接收到请求时,或者两者之间的某个时刻启动。初始化工
    作有init()方法负责执行完成;
  3. 调用:从第一次到以后的多次访问,都是只调用doGet()或doPost()方法;
  4. 销毁:停止服务器时调用destroy()方法,销毁实例。

2、filter:

实现javax.servlet包的Filter接口的三个方法init()、doFilter()、destroy(),空实现也行

  1. 启动服务器时加载过滤器的实例,并调用init()方法来初始化实例;
  2. 每一次请求时都只调用方法doFilter()进行处理;
  3. 停止服务器时调用destroy()方法,销毁实例。

3、listener:

servlet2.4规范中提供了8个listener接口,可以将其分为三类:

  • 第一类:与servletContext有关的listner接口。包括:ServletContextListener、ServletContextAttributeListener
  • 第二类:与HttpSession有关的Listner接口。包括:HttpSessionListner、HttpSessionAttributeListener、HttpSessionBindingListener、HttpSessionActivationListener;
  • 第三类:与ServletRequest有关的Listener接口,包括:ServletRequestListner、ServletRequestAttributeListener

web.xml 的加载顺序是:context- param -> listener -> filter -> servlet

三、使用方式

listener:

public class TestListener implements HttpSessionListener,ServletRequestListener,ServletRequestAttributeListener {
	private Logger logger = LoggerFactory.getLogger(TestListener.class);
	//sessionListener start!
	public void sessionCreated(HttpSessionEvent arg0) {
		logger.info(".......TestListener sessionCreated().......");
	} 
	public void sessionDestroyed(HttpSessionEvent arg0) {
		logger.info(".......TestListener sessionDestroyed().......");
	} 
	//sessionListener end!
	//requestListener start!
	public void requestInitialized(ServletRequestEvent arg0) {
		logger.info("......TestListener requestInitialized()......");
	} 
	public void requestDestroyed(ServletRequestEvent arg0) {
		logger.info("......TestListener requestDestroyed()......");
	} 
	//requestListener end!
	//attributeListener start!
	public void attributeAdded(ServletRequestAttributeEvent srae) {
		logger.info("......TestListener attributeAdded()......");
	} 
	public void attributeRemoved(ServletRequestAttributeEvent srae) {
		logger.info("......TestListener attributeRemoved()......");
	}
	public void attributeReplaced(ServletRequestAttributeEvent srae) {
		logger.info("......TestListener attributeReplaced()......");
	} 
	//attributeListener end!
}

Filter:

public class TestFilter implements Filter {
	private Logger logger = LoggerFactory.getLogger(TestFilter.class);
	public void destroy() {
		logger.info("..............execute TestFilter destory()..............");
	} 
	public void doFilter(ServletRequest arg0, ServletResponse arg1,FilterChain arg2) throws IOException, ServletException {
		logger.info("..............execute TestFilter doFilter()..............");
		arg2.doFilter(arg0, arg1);
	} 
	public void init(FilterConfig arg0) throws ServletException {
		logger.info("..............execute TestFilter init()..............");
	}
}

Servlet:

public class TestServlet extends HttpServlet {
	private Logger logger = LoggerFactory.getLogger(TestServlet.class);
	private static final long serialVersionUID = -4263672728918819141L;
	@Override
	public void init() throws ServletException {
		logger.info("...TestServlet init() init..........");
		super.init();
	} 
	@Override
	public void destroy() {
		logger.info("...TestServlet init() destory..........");
		super.destroy();
	} 
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		this.doPost(req, resp);
	} 
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		logger.info("...TestServlet doPost() start..........");
		//操作attribute
		request.setAttribute("a", "a");
		request.setAttribute("a", "b");
		request.getAttribute("a");
		request.removeAttribute("a");
		//操作session
		request.getSession().setAttribute("a", "a");
		request.getSession().getAttribute("a");
		request.getSession().invalidate();
		logger.info("...TestServlet doPost() end..........");
	}
}

配置XML:

<!-- 测试filter -->
<filter>
	<filter-name>TestFilter</filter-name>
	<filter-class>com.xy.web.filter.TestFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>TestFilter</filter-name>
	<url-pattern>*.do</url-pattern>
</filter-mapping>

<!-- 测试servlet -->
<servlet>
	<servlet-name>TestServlet</servlet-name>
	<servlet-class>com.xy.web.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>TestServlet</servlet-name>
	<url-pattern>/*</url-pattern>
</servlet-mapping>

<!-- 测试listener -->
<listener>
	<listener-class>com.xy.web.listener.TestListener</listener-class>
</listener>

第六章 常用模板

Filter-解决乱码:

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

/**
 * 解决全站乱码问题,处理所有的请求
 */
@WebFilter("/*")
public class CharchaterFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse rep, FilterChain filterChain) throws IOException, ServletException {
        //将父接口转为子接口
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) rep;
        //获取请求方法
        String method = request.getMethod();
        //解决post请求中文数据乱码问题
        if(method.equalsIgnoreCase("post")){
            request.setCharacterEncoding("utf-8");
        }
        //处理响应乱码
        response.setContentType("text/html;charset=utf-8");
        filterChain.doFilter(request,response);
    }

    @Override
    public void destroy() {

    }
}

数据源(druid) db.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root

filters=wall,stat
maxActive=20
initialSize=3
maxWait=5000
minIdle=3
maxIdle=15
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=300000
validationQuery=SELECT 'x'
testWhileIdle=true
testOnBorrow=false
testOnReturn=false
maxOpenPreparedStatements=20
removeAbandoned=true
removeAbandonedTimeout=1800
logAbandoned=true

日志logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!-- 定义参数常量 -->
    <!-- 日志级别 TRACE<DEBUG<INFO<WARN<ERROR -->
    <!-- logger.trace("msg") logger.debug... -->
    <property name="log.level" value="debug"/>
    <property name="log.maxHistory" value="30"/>
    <property name="log.filePath" value="E:/log"/>
    <property name="log.pattern"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
    <!-- 控制台输出设置 -->
    <appender name="consoleAppender"
              class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>
    <!-- DEBUG级别文件记录 -->
    <appender name="debugAppender"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 文件路径 -->
        <file>${log.filePath}/debug.log</file>
        <!-- 滚动日志文件类型,就是每天都会有一个日志文件 -->
        <rollingPolicy
                class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 文件名称 -->
            <fileNamePattern>${log.filePath}/debug/debug.%d{yyyy-MMdd}.log.gz
            </fileNamePattern>
            <!-- 文件最大保存历史数量 -->
            <maxHistory>${log.maxHistory}</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- DEBUG级别文件记录 -->
    <appender name="errorAppender"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 文件路径 -->
        <file>${log.filePath}/debug.log</file>
        <!-- 滚动日志文件类型,就是每天都会有一个日志文件 -->
        <rollingPolicy
                class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 文件名称 -->
            <fileNamePattern>${log.filePath}/debug/debug.%d{yyyy-MMdd}.log.gz
            </fileNamePattern>
            <!-- 文件最大保存历史数量 -->
            <maxHistory>${log.maxHistory}</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- INFO -->
    <appender name="infoAppender"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 文件路径 -->
        <file>${log.filePath}/info.log</file>
        <rollingPolicy
                class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 文件名称 -->
            <fileNamePattern>${log.filePath}/info/info.%d{yyyy-MM-dd}.log.gz
            </fileNamePattern>
            <!-- 文件最大保存历史数量 -->
            <maxHistory>${log.maxHistory}</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- com.xinzhi开头的日志对应形式 -->
    <logger name="cn.itnanls" level="${log.level}" additivity="true">
        <appender-ref ref="debugAppender"/>
        <appender-ref ref="infoAppender"/>
        <appender-ref ref="errorAppender"/>
    </logger>
    <!-- <root> 是必选节点,用来指定最基础的日志输出级别,只有一个level属性 -->
    <root level="info">
        <appender-ref ref="consoleAppender"/>
    </root>
    <!-- 捕捉sql开头的日志 -->
    <appender name="MyBatis"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.filePath}/sql_log/mybatis-sql.log</file>
        <rollingPolicy
                class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${log.filePath}/sql_log/mybatissql.log.%d{yyyy-MM-dd}</FileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder
                class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%thread|%d{yyyy-MM-dd
                HH:mm:ss.SSS}|%level|%logger{36}|%m%n
            </pattern>
        </encoder>
    </appender>
    <logger name="sql" level="DEBUG">
        <appender-ref ref="MyBatis"/>
    </logger>
</configuration>

日志需要依赖的包

		<dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

		这个factory加载配置文件用!!!
		<dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

Servlet-退出

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/exitServlet")
public class ExitServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.销毁session
        request.getSession().invalidate();

        //2.跳转登录页面
        response.sendRedirect(request.getContextPath()+"/login.html");
    }

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

Util-JDBCUtiles

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/*
	1. 声明静态数据源成员变量
	2. 创建连接池对象
	3. 定义公有的得到数据源的方法
	4. 定义得到连接对象的方法
	5. 定义关闭资源的方法
 */
public class JDBCUtils {
	// 1.	声明静态数据源成员变量
	private static DataSource ds;

	// 2. 创建连接池对象
	static {
		// 加载配置文件中的数据
		InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
		Properties pp = new Properties();
		try {
			pp.load(is);
			// 创建连接池,使用配置文件中的参数
			ds = DruidDataSourceFactory.createDataSource(pp);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 3. 定义公有的得到数据源的方法
	public static DataSource getDataSource() {
		return ds;
	}

	// 4. 定义得到连接对象的方法
	public static Connection getConnection() throws SQLException {
		return ds.getConnection();
	}

	// 5.定义关闭资源的方法
	public static void close(Connection conn, Statement stmt, ResultSet rs) {
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {}
		}

		if (stmt != null) {
			try {
				stmt.close();
			} catch (SQLException e) {}
		}

		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {}
		}
	}

	// 6.重载关闭方法
	public static void close(Connection conn, Statement stmt) {
		close(conn, stmt, null);
	}
}

Util-Jedis

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * Jedis工具类
 */
public final class JedisUtil {
    private static JedisPool jedisPool;

    static {
        //读取配置文件
        InputStream is = JedisPool.class.getClassLoader().getResourceAsStream("jedis.properties");
        //创建Properties对象
        Properties pro = new Properties();
        //关联文件
        try {
            pro.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //获取数据,设置到JedisPoolConfig中
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
        config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle")));

        //初始化JedisPool
        jedisPool = new JedisPool(config, pro.getProperty("host"), Integer.parseInt(pro.getProperty("port")));


    }


    /**
     * 获取连接方法
     */
    public static Jedis getJedis() {
        return jedisPool.getResource();
    }

    /**
     * 关闭Jedis
     */
    public static void close(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }
}
  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值