01.web的基本概念、web服务器讲解
02.Tomcat详解
03.Http讲解
04.Maven
05.Servlet
06.Cookie、Session
07.JSP
08.JavaBean
09.MVC三层架构
10.Filter
11.监听器
12.过滤器、监听器常见应用
13.JDBC
web开发:
在Java中,动态web资源开发的技术统称为Javaweb
**web应用程序:**可以提供浏览器访问的程序;
web应用程序编写完毕后,若想提供给外界访问:需要一个服务器来统一管理;
页面动态展示。
缺点:
- 加入服务器的动态web资源出现了错误,我们需要重新编写我们的后台程序,重新发布;
- 停机维护
优点:
- Web页面可以动态更新,所有用户看到都不是同一个页面
- 它可以与数据库交互(数据持久化)
ASP:
<hl>
<hl><hl>
<hl>
<hl>
<hl>
<%
system.out.println("hello");
%>
<hl>
<h1>
<hl><hl>
<hl>
php:
JSP/Servlet:
B/S:浏览和服务器
C/S:客户端和服务器
服务器是一种被动的操作,用来处理用户的一些请求和给用户一些响应消息;
IIS
微软的;ASP…,Windows中自带的
Tomcat
面向百度编程;
- Tomcat是Apache软件基金会(Apache Software Foundation)的jakarta项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。由于有了Sun的参与和支持,最新的Servlet和JSP规范总是能在Tomcat中得到体现,Tomcat5支持最新的Servlet2.4和JSP 2.0规范。因为Tomcat技术先进、性能稳定,而且免费,因而深受Java爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web应用服务器。
- Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache服务器,可利用它响应HTML(标准通用标记语言下的一个应用)页面的访问请求,实际上Tomcat是Apache 服务器的扩展,但运行时它是独立运行的,所以当你运行tomcat时,它实际上作为一个与Apache 独立的进程单独运行的。
- 诀窍是,当配置正确时,Apache为HTML页面服务,而Tomcat 实际上运行JSP页面和Servlet.另外,Tomcat和IIS等Web服务器一样,具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式。不过,Tomcat处理静态HTML的能力不如Apache服务器。目前Tomcat最新版本为9.0。
可以配置启动的端口号
<Connector port="8081" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"/>
可以配置主机的名称
<Host name="[www.qinjiang.com](http://ww.qinjiang.com/)" appBase="webapps"
unpackWARs="true" autoDeploy="true">
高难度面试题:
请你谈一谈网站是如何访问的
输入一个域名;回车
检查本机的C:\windows\System32\drivers\etc\hosts配置文件下有没有这个域名映射;
a. 有:直接返回对应的ip地址,这个地址中,有我们需要访问的web程序,可以直接访问
127.0.0.1 [www.qinjiang.com](http://www.qinjiang.com/)
b. 没有:去DNS服务器找,找到的话就返回,找不到就返回找不到
可以配置一下环境变量(可选性)
HTTP(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上。
客户端 – 发请求(Request) – 服务器
百度:
Request URL:[https://www.baidu.com/](https://www.baidu.com/) 请求地址
Request Method:GET get方法/post方法
Status Code:200 oK 状态码:200
Remote(远程) Address:14.215.177.39:443
Accept:text/html
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.9 语言
Cache-Control:max-age=0
Connection:keep-alive
1.请求行
get
:请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址栏显示数据内容,不安全,但高post
:请求能够携带的参数没有限制,大小没有限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效。2.消息头
Accept:告诉浏览器,它所支持的数据类型
Accept-Encoding:支持部种询码格式 GBK UTF-8 GB2312 ISO8859-1
Accept-Language:告诉湖览器,它的语言环境
Cache-Control:缓存控制
Connection:告诉浏览器,请求完成是断开还是保持连续
HOST:主机..../.
百度:
Cache-Control:private 缓存控制
Connection:Keep-Alive 连接
Content-Encoding:gzip
Content-Type:text/htm1
1.响应体
Accept:告诉测览器,它所支持的数据类型
Accept-Encoding:支持哪种编码格式 GBK UTF-8 GB2312 ISo8859-1
Accept-Language:告诉浏览器,它的语言环境
Cache-Control:缓存控制
Connection:告诉浏览器,请求完成是断开还是保持连接
HOST:主机../.
Refresh:告诉容户端,多久刷新一次
Location:址网页重新定位
2.响应状态码
200:请求响应成功 200
3**:请求重定向
我们目前用来就是方便导入jar包的!
Maven的核心思想:约定大于配置
Maven会规定好你该如何去编写我们的Java代码,必须要按照这个规范来
<mirror>
<id>alimavenid>
<mirrorof>centralmirrorof>
<name>aliyun mavenname>
<url>[http://maven.aliyun.com/nexus/content/groups/public/](http://maven.aliyun.com/nexus/content/groups/public/)url>
mirror>
在本地的仓库,远程仓库;
建立一个本地仓库:localRepository
<localRepository>D:\Environment\apache-maven-3.6.2\maven-repolocalRepository>
把实现了Servlet接口的java程序叫做,Servlet
Servlet接口Sun公司有两个默认的实现类:HttpServlet
,GenericServlet
1.构建一个普通的Maven项目,删掉里面的src目录,以后我们的学习就在这个项目里面建立Moudel,这个空的工程就是Maven主工程;
2.关于Maven父子工程的理解:
父项目中会有
<modules>
<module>servlet-01module>
modules>
子项目中会有
<parent>
<artifactId>javaweb-02-servletartifactId>
<version>1.0-SNAPSHOTveresin>
parent>
父项目中的java子项目可以直接使用
son extends father
3.Maven环境优化
4.编写一个Servlet程序
HttpServlet
public class HelloServlet extends HttpServlet{
//由于get或post只是请求实现的不同的方式,可以互相调用,业务逻辑都一样;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
//ServletOutputStream OutputStream=res.getOutputStream();
PrintWriter writer=resp.getWriter();//响应流
writer.print("Hello,Servlet");
}
@Override
protected void doPost(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
doGet(req,resp);
}
}
5.编写Servlet的映射
为什么需要映射:我们写的是Java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务器中注册我们写的Servlet,还需要给他一个浏览器能够访问的路径;
<servlet>
<servlet-name>helloservlet-name>
<servlet-class>com.kuang.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
6.配置Tomcat
注意:配置项目发布的路径就可以了
7.启动测试
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello2url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello3url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello4url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello5url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello/*url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/*url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>*.qinjiangurl-pattern>
servlet-mapping>
指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求;
<servlet>
<servlet-name>errorservlet-name>
<servlet-class>com.kuang.servlet.ErrorServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>errorservlet-name>
<url-pattern>/*url-pattern>
servlet-mapping>
web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext
对象,它代表了当前的web应用:
Servlet
中保存的数据,可以在另一个Servlet
中拿到;web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest
对象,代表响应的一个HttpServletResponse
;
HttpServletRequest
HttpServletResponse
简单分类
负责向浏览器发送数据的方法
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
负责向浏览器发送响应头的方法
Response下载文件
Response验证码实现
Response重定向
Request应用
会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称为会话。
有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学,曾经来过,称之为有状态会话。
cookie
session
常见案例:网站登录之后,你下次不用再登录了,第二次访问直接就上去了!
Cookies
是某些网站为了辨别用户身份而储存在用户本地终端上的数据(通常经过加密)。
简单来说: Cookie 存放在客户端,一般用来保存用户信息。
1.从请求中拿到cookie信息
2.服务器响应给客户端cookie
Cookie[] cookies=req.getCookies();//获得Cookie
cookie.getName();//获得cookie中的key
cookie.getValue();//获得cookie中的value
new Cookie("lastLoginTime",System.currentTimeMillis()+"")://新建一个cookie
cookie.setMaxAge(24*60*60);//设置cookie的有效期
resp.addCookie(cookie);//响应给客户端一个cookie
cookie:一般会保存在本地的用户目录下appdata;
删除cookie:
如何在项目中使用 Cookie 呢?
我这里以 Spring Boot 项目为例。
@GetMapping("/change-username")
public String setCookie(HttpServletResponse response) {
// 创建一个 cookie
Cookie cookie = new Cookie("username", "Jovan");
//设置 cookie过期时间
cookie.setMaxAge(7 * 24 * 60 * 60); // expires in 7 days
//添加到 response 中
response.addCookie(cookie);
return "Username is changed!";
}
@GetMapping("/")
public String readCookie(@CookieValue(value = "username", defaultValue = "Atta") String username) {
return "Hey! My username is " + username;
}
@GetMapping("/all-cookies")
public String readAllCookies(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
return Arrays.stream(cookies)
.map(c -> c.getName() + "=" + c.getValue()).collect(Collectors.joining(", "));
}
return "No cookies";
}
什么是Session?
Session和Cookie的区别:
Cookie
和 Session
都是用来跟踪浏览器用户身份的会话方式,但是两者的应用场景不太一样。
Cookie 一般用来保存用户信息 比如①我们在 Cookie 中保存已经登录过得用户信息,下次访问网站的时候页面可以自动帮你登录的一些基本信息给填了;②一般的网站都会有保持登录也就是说下次你再访问网站的时候就不需要重新登录了,这是因为用户登录的时候我们可以存放了一个 Token 在 Cookie 中,下次登录的时候只需要根据 Token 值来查找用户即可(为了安全考虑,重新登录一般要将 Token 重写);③登录一次网站后访问网站其他页面不需要重新登录。
Session 的主要作用就是通过服务端记录用户的状态。 典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户了。
Cookie 数据保存在客户端(浏览器端),Session 数据保存在服务器端。
Cookie 存储在客户端中,而Session存储在服务器上,相对来说 Session 安全性更高。如果使用 Cookie 的一些敏感信息不要写入 Cookie 中,最好能将 Cookie 信息加密然后使用到的时候再去服务器端解密。
如何使用Session-Cookie方案进行十分验证?
很多时候我们都是通过 SessionID
来实现特定的用户,SessionID
一般会选择存放在 Redis 中。举个例子:
SessionID
的 Cookie
SessionID
带上,这样后端就知道你的身份状态了。Session
,并将 Session
信息存储起来。SessionID
,写入用户的 Cookie
。Cookie
将与每个后续请求一起被发送出去。Cookie
上的 SessionID
与存储在内存中或者数据库中的 Session
信息进行比较,以验证用户的身份,返回给用户客户端响应信息的时候会附带用户当前的状态。使用 Session
的时候需要注意下面几个点:
Session
的关键业务一定要确保客户端开启了 Cookie
。Session
的过期时间。多服务器节点下 Session-Cookie 方案如何做?
Session-Cookie 方案在单体环境是一个非常好的身份认证方案。但是,当服务器水平拓展成多节点时,Session-Cookie 方案就要面临挑战了。
举个例子:假如我们部署了两份相同的服务 A,B,用户第一次登陆的时候 ,Nginx 通过负载均衡机制将用户请求转发到 A 服务器,此时用户的 Session
信息保存在 A 服务器。结果,用户第二次访问的时候 Nginx 将请求路由到 B 服务器,由于 B 服务器没有保存 用户的 Session
信息,导致用户需要重新进行登陆。
我们应该如何避免上面这种情况的出现呢?
有几个方案可供大家参考:
某个用户的所有请求都通过特性的哈希策略分配给同一个服务器处理。这样的话,每个服务器都保存了一部分用户的 Session
信息。服务器宕机,其保存的所有 Session
信息就完全丢失了。
每一个服务器保存的 Session
信息都是互相同步的,也就是说每一个服务器都保存了全量的 Session
信息。每当一个服务器的 Session
信息发生变化,我们就将其同步到其他服务器。这种方案成本太大,并且,节点越多时,同步成本也越高。
单独使用一个所有服务器都能访问到的数据节点(比如缓存)来存放 Session
信息。为了保证高可用,数据节点尽量要避免是单点。
如果没有 Cookie 的话 Session 还能用吗?
这是一道经典的面试题!
一般是通过 Cookie
来保存 SessionID
,假如你使用了 Cookie
保存 SessionID
的方案的话, 如果客户端禁用了 Cookie
,那么 Session
就无法正常工作。
但是,并不是没有 Cookie
之后就不能用 Session
了,比如你可以将 SessionID
放在请求的 url 里面https://javaguide.cn/?Session_id=xxx
。这种方案的话可行,但是安全性和用户体验感降低。当然,为了你也可以对 SessionID 进行一次加密之后再传入后端。
Java Server Pages:Java服务器端页面,也和Servlet一样,用于动态web技术!
最大的特点:
思路:JSP到底怎么执行的?
Tomcat中有一个work目录;
IDEA中使用Tomcat的会在IDEA的Tomcat中生产一个work目录;
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet!
JSP最终也会被转换为一个Java类!
JSP本质上就是一个Servlet.
//初始化
public void _jspInit(){
}
//销毁
public void _jspDestory(){
}
//JSPService
public void _jspService(.HttpServletRequest request,HttpServletResponse response)
final javax.servlet.jsp.PageContext pageContext; //页面上下文
javax.servlet.http.HttpSession session = null; //session
final javax.servlet.ServletContext application; //applicationContext
final javax.servlet.ServletConfig config; //config
javax.servlet.jsp.JspWriter out = null; //out
final java.lang.Object page = this; //page:当前
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
【补充】:
JSP工作原理
JSP
是一种Servlet
,但是与HttpServlet
的工作方式不太一样。HttpServlet
是先由源代码编译为class
文件后部署到服务器下,为先编译后部署。而JSP
则是先部署后编译。JSP
会在客户端第一次请求JSP
文件时被编译为HttpJspPage
类(接口Servlet
的一个子类)。该类会被服务器临时存放在服务器工作目录里面。下面通过实例给大家介绍。 工程JspLoginDemo
下有一个名为login.jsp
的Jsp
文件,把工程第一次部署到服务器上后访问这个Jsp
文件,我们发现这个目录下多了下图这两个东东。 .class
文件便是JSP
对应的Servlet
。编译完毕后再运行class文件来响应客户端请求。以后客户端访问login.jsp
的时候,Tomcat
将不再重新编译JSP
文件,而是直接调用class
文件来响应客户端请求。
只会在客户端第一次请求的时候被编译 ,因此第一次请求JSP
时会感觉比较慢,之后就会感觉快很多。如果把服务器保存的class文件删除,服务器也会重新编译JSP
。
开发Web程序时经常需要修改JSP
。Tomcat能够自动检测到JSP
程序的改动。如果检测到JSP
源代码发生了改动。Tomcat会在下次客户端请求JSP
时重新编译JSP
,而不需要重启Tomcat
。这种自动检测功能是默认开启的,检测改动会消耗少量的时间,在部署Web
应用的时候可以在web.xml
中将它关掉。
任何语言都有自己的语法,Java中有。JSP作为Java技术的一种应用,它拥有一些自己的扩充语法(了解,知道即可),Java所有语法都支持!
JSP表达式
<%--JSP表达式
作用:用来将程序的输出,输出到客户端
<%=变量或者表达式%>
--%>
<%= new java.util.Date()%>
jsp脚本片段
<%--jsp脚本片段--%>
<%
int sum=0;
for (int i=1;i<100;i++){
sum+=i;
}
out.println("Sum="
+sum+"");
%>
JSP声明
<%!
static{
System.out.println("Loading Servlet!");
}
private int globalvar=0;
public void kuang(){
System.out.println("进入了方法kuang!");
}
%>
JSP声明:会被编译到JSP生成Java的类中!其他的,都会被生成到_jspService方法中!
在JSP,嵌入Java代码即可!
<%%>
<%=%>
<%!%>
<%--注释--%>
JSP的注释不会在客户端显示,HTML就会!
JSP指令
<%@page args....%>
<%@include file=""%>
<%--@include会将两个页面合二为一--%>
<%@include file="common/header.jsp"%>
<h1>网页主体</h1>
<%@include file="common/footer.jsp"%>
<hr>
<%--JSP标签
jsp:include:拼接页面,本质还是三个
--%>
<jsp:include page="/common/header.jsp"/>
<h1>网页主体</h1>
<jsp:include page="/common/footer.jsp"/>
9大内置对象
request
:封装客户端的请求,其中包含来自GET或POST请求的参数;response
:封装服务器对客户端的响应;pageContext
:通过该对象可以获取其他对象;session
:封装用户会话的对象;application
:封装服务器运行环境的对象,【ServletContext】存东西;out
:输出服务器响应的输出流对象;config
:Web应用的配置对象,【ServletConfig】;page
:JSP页面本身(相当于Java程序中的this);exception
:封装页面抛出异常的对象。四种作用域
JSP中的四种作用域包括page、request、session和application,具体来说:
如何实现JSP或Servlet的单线程模式
对于JSP页面,可以通过page指令进行设置。 <%@page isThreadSafe="false"%>
对于Servlet,可以让自定义的Servlet实现SingleThreadModel标识接口。
说明:如果将JSP或Servlet设置成单线程工作模式,会导致每个请求创建一个Servlet实例,这种实践将导致严重的性能问题(服务器的内存压力很大,还会导致频繁的垃圾回收),所以通常情况下并不会这么做。
JSP标签
<%--jsp:include--%>
<%--
http://localhost:8080/jsptag.jsp?name=kuangshen&age=12
--%>
<jsp:forward page="/jsptag2.jsp">
<jsp:param name="name" value="kuangshen"></jsp:param>
<jsp:param name="age" value="12"></jsp:param>
</jsp:forward>
JST表达式
JSTL标签库的使用就是为了弥补HTML的不足;它自定义许多标签,可以供我们使用,标签的功能和java代码一样!
JSTL核心标签
核心标签是最常用的 JSTL标签。引用核心标签库的语法如下:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
JSTL标签库使用步骤:
实体类
JavaBean有特定的写法
一般用来和数据库的字段做映射 ORM;
ORM:对象关系映射
class people{
private int id;
private String name;
private int id;
private String address;
}
class A{
new People(1,"安娜1号",3,"西安");
new People(2,"安娜2号",3,"西安");
new People(3,"安娜3号",3,"西安");
}
什么是MVC:Model view Controller 模型、视图、控制器
用户直接访问控制层,控制层就可以直接操作数据库;
servlet--CRUD-->数据库
弊端;程序十分臃肿,不利于维护
servlet的代码中:处理请求、响应、视图跳转、处理JDBC、处理业务代码、处理逻辑代码
架构:没有什么是加一层解决不了的!
程序员调用
|
JDBC
|
Mysql Oracle SqlServer...
Model:
View:
Controller:
登录--->接收用户的登录请求--->处理用户请求(获取用户登录的参数,username,password)---->
交给业务层处理登录业务(判断用户名密码是否正确)--->Dao层查询用户名和密码是否正确
Filter:过滤器,用来过滤网站的数据;
Filter过滤
过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以我们可以在过滤后的结果来应用其他Stream操作(比如forEach)。forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作,所以我们不能在forEach之后来执行其他Stream操作。
// 测试 Filter(过滤)
stringList
.stream()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);//aaa2 aaa1
forEach 是为 Lambda 而设计的,保持了最紧凑的风格。而且 Lambda 表达式本身是可以重用的,非常方便。
实现Filter接口,重写对应的方法即可
public class CharacterEncodingFilter implements Filter {
//初始化:web服务器启动,就以及初始化了,随时等待过滤对象出现!
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharacterEncodingFilter初始化");
}
//Chain : 链
/*
1. 过滤中的所有代码,在过滤特定请求的时候都会执行
2. 必须要让过滤器继续同行
chain.doFilter(request,response);
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=UTF-8");
System.out.println("CharacterEncodingFilter执行前....");
chain.doFilter(request,response); //让我们的请求继续走,如果不写,程序到这里就被拦截停止!
System.out.println("CharacterEncodingFilter执行后....");
}
//销毁:web服务器关闭的时候,过滤器会销毁
public void destroy() {
System.out.println("CharacterEncodingFilter销毁");
}
}
在web.xml中配置Filter
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>com.kuang.filter.CharacterEncodingFilterfilter-class>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/servlet/*url-pattern>
filter-mapping>
实现一个监听器的接口;(有n种监听器)
package com.kuang.listener;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
依赖的jar包
//统计网站在线人数 : 统计session
public class OnlineCountListener implements HttpSessionListener {
//创建session监听: 看你的一举一动
//一旦创建Session就会触发一次这个事件!
public void sessionCreated(HttpSessionEvent se) {
ServletContext ctx = se.getSession().getServletContext();
System.out.println(se.getSession().getId());
Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
if (onlineCount==null){
onlineCount = new Integer(1);
}else {
int count = onlineCount.intValue();
onlineCount = new Integer(count+1);
}
ctx.setAttribute("OnlineCount",onlineCount);
}
//销毁session监听
//一旦销毁Session就会触发一次这个事件!
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext ctx = se.getSession().getServletContext();
Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
if (onlineCount==null){
onlineCount = new Integer(0);
}else {
int count = onlineCount.intValue();
onlineCount = new Integer(count-1);
}
ctx.setAttribute("OnlineCount",onlineCount);
}
/*
Session销毁:
1. 手动销毁 getSession().invalidate();
2. 自动销毁
*/
}
<!--注册监听器-->
<listener>
<listener-class>com.kuang.listener.OnlineCountListener</listener-class>
</listener>
监听器:GUI编程中经常使用;
public class TestPanel {
public static void main(String[] args) {
Frame frame = new Frame("中秋节快乐"); //新建一个窗体
Panel panel = new Panel(null); //面板
frame.setLayout(null); //设置窗体的布局
frame.setBounds(300,300,500,500);
frame.setBackground(new Color(0,0,255)); //设置背景颜色
panel.setBounds(50,50,300,300);
panel.setBackground(new Color(0,255,0)); //设置背景颜色
frame.add(panel);
frame.setVisible(true);
//监听事件,监听关闭事件
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
super.windowClosing(e);
}
});
}
}
用户登录之后才能进入主页!用户注销后就不能进入主页了!
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
if (request.getSession().getAttribute(Constant.USER_SESSION)==null){
response.sendRedirect("/error.jsp");
}
chain.doFilter(request,response);
JDBC
需要jar包的支持:
实验环境搭建
**CREATE TABLE users(
id INT PRIMARY KEY,
`name` VARCHAR(40),
`password` VARCHAR(40),
email VARCHAR(60),
birthday DATE
);
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(1,'张三','123456','zs@qq.com','2000-01-01');
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(2,'李四','123456','ls@qq.com','2000-01-01');
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(3,'王五','123456','ww@qq.com','2000-01-01');
SELECT * FROM users;**
导入数据库依赖
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
JDBC固定步骤
public class TestJdbc {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//配置信息
//useUnicode=true&characterEncoding=utf-8 解决中文乱码
String url="jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.连接数据库,代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//3.向数据库发送SQL的对象Statement,PreparedStatement : CRUD
Statement statement = connection.createStatement();
//4.编写SQL
String sql = "select * from users";
//5.执行查询SQL,返回一个 ResultSet : 结果集
ResultSet rs = statement.executeQuery(sql);
while (rs.next()){
System.out.println("id="+rs.getObject("id"));
System.out.println("name="+rs.getObject("name"));
System.out.println("password="+rs.getObject("password"));
System.out.println("email="+rs.getObject("email"));
System.out.println("birthday="+rs.getObject("birthday"));
}
//6.关闭连接,释放资源(一定要做) 先开后关
rs.close();
statement.close();
connection.close();
}
}
预编译SQL
public class TestJDBC2 {
public static void main(String[] args) throws Exception {
//配置信息
//useUnicode=true&characterEncoding=utf-8 解决中文乱码
String url="jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.连接数据库,代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//3.编写SQL
String sql = "insert into users(id, name, password, email, birthday) values (?,?,?,?,?);";
//4.预编译
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,2);//给第一个占位符? 的值赋值为1;
preparedStatement.setString(2,"狂神说Java");//给第二个占位符? 的值赋值为狂神说Java;
preparedStatement.setString(3,"123456");//给第三个占位符? 的值赋值为123456;
preparedStatement.setString(4,"[email protected]");//给第四个占位符? 的值赋值为1;
preparedStatement.setDate(5,new Date(new java.util.Date().getTime()));//给第五个占位符? 的值赋值为new Date(new java.util.Date().getTime());
//5.执行SQL
int i = preparedStatement.executeUpdate();
if (i>0){
System.out.println("插入成功@");
}
//6.关闭连接,释放资源(一定要做) 先开后关
preparedStatement.close();
connection.close();
}
}
事务
要么都成功,要么都失败!
ACID原则:保证数据的安全。
开启事务
事务提交 commit()
事务回滚 rollback()
关闭事务
转账:
A:1000
B:1000
A(900) --100--> B(1100)
Junit单元测试
依赖
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
简单使用
@Test注解只有在方法上有效,只要加了这个注解的方法,就可以直接运行!
@Test
public void test(){
System.out.println("Hello");
}
搭建一个环境
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(40),
money FLOAT
);
INSERT INTO account(`name`,money) VALUES('A',1000);
INSERT INTO account(`name`,money) VALUES('B',1000);
INSERT INTO account(`name`,money) VALUES('C',1000);
@Test
public void test() {
//配置信息
//useUnicode=true&characterEncoding=utf-8 解决中文乱码
String url="jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
Connection connection = null;
//1.加载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
//2.连接数据库,代表数据库
connection = DriverManager.getConnection(url, username, password);
//3.通知数据库开启事务,false 开启
connection.setAutoCommit(false);
String sql = "update account set money = money-100 where name = 'A'";
connection.prepareStatement(sql).executeUpdate();
//制造错误
//int i = 1/0;
String sql2 = "update account set money = money+100 where name = 'B'";
connection.prepareStatement(sql2).executeUpdate();
connection.commit();//以上两条SQL都执行成功了,就提交事务!
System.out.println("success");
} catch (Exception e) {
try {
//如果出现异常,就通知数据库回滚事务
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}