javaweb
Cookie.Session
会话
会话: 用户打开一个浏览器,点击了很多超链接,访问多个文本资源,关闭浏览器,这个过程可以称之为会话:
有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学曾经来过,称之为有状态会话;
一个网站该怎么证明你来过呢?
服务端给客户端一个"信件",客户端下次访问服务器带上"信件"就可以了;这个客户端持有的"信件"就是cookie
服务器登记你来过了,下次你再来的时候服务器来匹配你;服务器持有的登记信息就是session
保存会话的两种技术
cookie: 客户端技术(响应请求)
session: 服务器技术,利用这个技术,可以保存用户的会话信息.我们就可以把信息或者数据放在session中
比如网站登录之后,下次就不用再登录了,第二次访问直接就可以登录了
如下为设置Cookie以及获取cookie的方法:(第一次无法显示,需要先进性刷新)
//保存用户上一次访问的事件
public class CookieDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//服务器告诉你你来的时间,然后把这个事件封装为一个信件,你下次来,我就知道你来了
//解决中文乱码
req.setCharacterEncoding("GBK");
resp.setCharacterEncoding("GBK");
PrintWriter out = resp.getWriter();//先获取响应输出方法
//Cookie,服务器端从客户端获取
Cookie[] cookies = req.getCookies();//这里返回数组,说明Cookie可能存在多个
//判断cookie是否存在
if (cookies!=null){
//如果存在怎么办
out.write("你上一次访问的时间是:");
/* for (Cookie cookie : cookies) {
}*/
for (int i = 0; i <cookies.length ; i++) {
Cookie cookie = cookies[i];
//获取cookie的名字
if (cookie.getName().equals("lastLoginTime")) {
//获取cookie中的值
String value = cookie.getValue();//现在拿到的值是一个字符串
long l = Long.parseLong(value);//这样就把String类型转换位长整型的数字(时间戳)
Date date = new Date(l);//这样就变成了一个Date对象了
//out.write(date.toLocaleString());
out.write(String.valueOf(date));
}
}
}else {
out.write("这是您第一次访问");
}
//服务器给客户端响应一个cookie
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");//新建一个cookie
//System.currentTimeMillis()用来获取时间,后面加上""为了转换成字符串
cookie.setMaxAge(60);//设置cookie的最大生命时长,以秒为单位
resp.addCookie(cookie);//响应中添加上cookie
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
如下为cookie死亡方法:
先获取/s1的cookie,一般关闭浏览器之后cookie就会死亡,但是设置了cookie的声明周期之后,关闭浏览器再次打开就可以直接获取之前的cookie,此时再调用/s2使线程死亡之后就可以关闭cookie了
//服务器给客户端响应一个cookie
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");
cookie.setMaxAge(0);
resp.addCookie(cookie);
// 这样就可以强制使cookie死亡
//但是应该注意两边的cookie中 键的名字 应该相同
效果图如下:

Cookie

1,从请求中拿到cookie信息
2,服务器响应给客户端cookie
Cookie[] cookies = req.getCookies(); //获得Cookie
cookie.getName(); //获得cookie中的key
cookie.getValue(); //获得cookie中的vlaue
new Cookie("lastLoginTime", System.currentTimeMillis()+""); //新建一个cookie
cookie.setMaxAge(24*60*60); //设置cookie的有效期
resp.addCookie(cookie); //响应给客户端一个cookie
cookie一般会保存在本地用户的appdata目录下
需要注意的是:
一个cookie只能保存一个信息
一个web站点可以给浏览器发送多个cookie,最多存放20个cookie;
cookie大小有4kb的限制
最多有300个浏览器cookie上限
删除cookie的方法:
不设置有效期,关闭浏览器,自动失效,设置有效时间为0等;
编码解码:
URLEncoder.encode("秦疆","utf-8")//编码
URLDecoder.decode(cookie.getValue(),"UTF-8")//解码
Session(重点)

什么是session?
服务器会给每一个用户(浏览器)创建一个session对象
一个session独占一个浏览器,只要浏览器没有关闭,这个session就一直存在
用户登录之后,整个网站都可以访问,保存用户信息,保存购物车信息等…

session和cookie的区别
cookie是把用户的数据写给用户的浏览器,浏览器保存(可以保存多个)
session把用户的数据写倒用户独占session中,服务端保存,用户靠保存的session的id来进行访问(一般只保存重要的信息,以减少服务器自愿的浪费)
session和cookie对象都是由服务器创建,
不过session被服务器保留用来匹配用户,
cookie被服务器分发给(用户)浏览器用来进行下次访问的.
session使用场景:
public class SessionDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码问题
resp.setCharacterEncoding("utf-8");
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//得到Session
HttpSession session = req.getSession();
//给Session中存东西
session.setAttribute("name", new person("常振熙",22));
//获取Session 的ID
String id = session.getId();
//判断是不是新创建的Session
if (session.isNew()) {
resp.getWriter().write("session创建成功,id为:" + id);//print是打印,write()是往外写
} else {
resp.getWriter().write("session已经在服务器中存在了,id:" + id);
}
//session创建的时候用cookie来讲相当于做了什么事情
// Cookie cookie = new Cookie("JSESSIONID", "sessionId");
// resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
//得到Session中的对象
HttpSession session = req.getSession();
person p = (person) session.getAttribute("name");
System.out.println(p.toString());
//删除session中的name为"name"的键值对,这个键值对就是上面第11行代码中存的东西
HttpSession session = req.getSession();
session.removeAttribute("name");
//手动注销Session
session.invalidate();
session会话自动过期:
<!-- 设置session默认的消失时间-->
<session-config>
<!-- 以下为设置10分钟之后session自动失效,以分钟为单位-->
<session-timeout>10</session-timeout>
</session-config>
示意图如下:

JSP
什么是jsp?
java server pages: java服务器端页面,也和servlet一样,用于开发动态web技术
最大的特点就是写jsp就像在写html,
区别就是html只用给用户提供静态的代码,jsp页面中可以嵌入java代码,为用户提供动态数据
jsp原型:
思考:jsp到底是怎么执行的?
首先代码层面没有问题,那么就是在服务器内部工作
+tomcat中就有一个work目录,idea中使用tomcat后就会在idea的tomcat中生产一个work目录:

tomcat\Unnamed_javaweb-session-cookie\work\Catalina\localhost\XXXX\org\apache\jsp
按照上述地址一路点开会发现原本tomcat的jsp页面转变称为了java程序:

PS:
如果找不到jar包可以添加tomcat1的lib目录,里面有大量的jar包

浏览器向服务器发送请求时,不管访问什么资源,其实都是在访问servlet
如上图所示,jsp最终也会被转化称为一个java类
jsp本质上就是一个servlet
证据如下;

再次点开包后可以看到它继承了HttpServlet:

所以说jsp其实就是servlet
jsp源码中对应的三个方法如下:
//初始化
public void _jspInit() {
}
//销毁
public void _jspDestroy() {
}
//JSPService
public void _jspService(.HttpServletRequest request,HttpServletResponse response)
可以看出:
1.它会判断一些请求
2.内置一些对象(重点):
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:当前
HttpServletRequest request //请求
HttpServletResponse response //响应
3.如下是jsp源码中输出jsp页面前增加的代码
response.setContentType("text/html"); //设置响应的页面类型,所以jsp才能被转换成html
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
//注意此处,out,session都已经被定义好了,所以在jsp页面中不用定义这些可以直接进行调用
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
4.从3中可以知道.3的代码中变量都已经声明过了,所以以上这些对象我们可以再jsp页面中直接使用
5.如下是jsp页面从编写到显示的具体流程图:
注意,只有jsp代码被执行显示操作的过程中才会产生最下面的java代码和class文件


从jsp页面中可以知道:看似jsp是html中写java代码,其实是在java代码中输出前端代码,最后被编译为class文件并发送给服务器显示
只要是java代码就会原封不动的出书
如果是html代码就会被转换为:
out.write("<html>\r\n");
这样的格式并被输出到前端
jsp基础语法
首先创建一个普通的Maven项目,不使用webapp框架

创建普通项目之后还需要在pom.xml中手动导入以下四个依赖:
<dependencies>
<!-- servlet 的依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<!-- JSP的依赖-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
<!-- JSTL表达式的依赖-->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- JSTL表达式需要一些标签,这个就是standard标签库 -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
任何语言都有自己的语法,JAVA中有语法。 JSP 作为java技术的一种应用,它拥有一些自己扩充的语法(了解,知道即可!),Java所有语法都支持!
jsp表达式
<%--但是可以在jsp页面最上面手动导包,然后可以在下面直接new Date--%>
<%@ page import="java.util.*" %>
<%= new Date()%>
或者new完之后跟Java一样alt+回车这样就可以自动在钱买你添加响应的包
<%--JSP表达式
作用:用来将程序的输出,输出到客户端
<%= 变量或者一些表达式%>
--%>
<%= new java.util.Date()%>
自定义错误页面
error-code代表错误代码(404,500), location中是设置的错误页面

jsp脚本片段
<%--JSP脚本片段--%>
<%
int x=0;
for (int i = 0; i <10 ; i++) {
x+=i;//此处的意思为x=x+i
}
//注意,此处out在jsp源码中就已经被定义了,可以直接就进行调用
//注意,引号中还需要用+包裹变量
out.println("<h1>x="+x+"</h1>");
%>
脚本片段的再实现
注意,因为整个jsp页面都会被转化为java代码,所以jsp中的java变量名也不能重复
并且还需要注意在<%%>中的注释不能使用<%–xxx–%>而是使用java的注释//
<%
int x = 10;
out.println(x);
%>
<p>这是一个JSP文档</p>
<%
int y = 2;
out.println(y);
%>
<hr>
<%--在代码嵌入HTML元素--%>
<%--如下为java嵌套html再在html中嵌套java --%>
<%
for (int i = 0; i < 5; i++) {
%>
<h1>Hello,World <%=i%> </h1>
<%
}
%>
jsp声明:
<%!
static{
System.out.println("globavar就是全局变量的意思");
}
private int globavar=0;
public void xg(){
System.out.println("进入了xg方法中");
}
%>
JSP声明(<%!%>)会被编译到JSP生成Java的类中!其他的,就会被生成到_jspService方法中!
在jsp中嵌入java代码即可
<%%> //片段
<%=%> //表达式输出一个值
<%!%> //定义全局方法或者变量9
${} //el表达式,在里面也可以进行输出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"/>
九大内置对象以及作用域
- PageContext 存东西
- Request 存东西
- Response
- Session 存东西
- Application 【其实就是SerlvetContext】 存东西
- config 【SerlvetConfig】
- out
- page ,不用了解
- exception
示例:
pageContext.setAttribute("name1","秦疆1号"); //保存的数据只在一个页面中有效
request.setAttribute("name2","秦疆2号"); //保存的数据只在一次请求中有效,请求转发会携带这个数据
session.setAttribute("name3","秦疆3号"); //保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
application.setAttribute("name4","秦疆4号"); //保存的数据只在服务器中有效,从打开服务器到关闭服务器
//寻找的时候如下:(如下的四个查找) 从底层到高层寻找
String name1 = (String) pageContext.findAttribute("name1");
String name2 = (String) pageContext.findAttribute("name2");
String name3 = (String) pageContext.findAttribute("name3");
String name4 = (String) pageContext.findAttribute("name4");
从底层到高层(作用域):page->request->session->application(servletTontext)
通过pagecontext取出我们的值,但是我们可以通过寻找的方式来进行获取
jvm: 双亲委派机制:就是跟这个类似,一个一个的找,只会使用父类的包加载,父类找不到再用子类
这样就可以避免你的包跟java官方的包重名之后改为只调用你的包
注意,除了原本就各自定义的作用域之外,还可以手动定义作用域:
<%-- 这个方法是ctrl点开setAttribute时再点击实现类发现的, scope翻译过来就是作用域
public void setAttribute(String name, Object attribute, int scope) {
switch(scope) {
case 1:
this.mPage.put(name, attribute);
break;
case 2:
this.mRequest.put(name, attribute);
break;
case 3:
this.mSession.put(name, attribute);
break;
case 4:
this.mApp.put(name, attribute);
break;
default:
throw new IllegalArgumentException("Bad scope " + scope);
}
}
--%>
<%-- 再次点开PageContext的源码会发现以下作用域的具体体现常量
public static final int PAGE_SCOPE = 1;
public static final int REQUEST_SCOPE = 2;
public static final int SESSION_SCOPE = 3;
public static final int APPLICATION_SCOPE = 4;--%>
<%
pageContext.setAttribute("hello1","hello1",PageContext.SESSION_SCOPE);
//上面这句话等价于:session.setAttribute("hello1","hello1");
%>
两种跳转方法都一样
前端:pageContext.forward(“index,jsp”);
后端:resquest.getRequestDispatcher(“index.jsp”).forward(request,response)
使用场景;
request:客户端向服务器发送请求,产生的数据,用户看完就没用了,类似于垃圾桶上的一次性塑料袋,用户用完就没用了!
session:客户端向服务器发送请求,产生的数据,用户用完一会还有用,类似于垃圾桶本身;用完还能用
application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,类似于垃圾处理厂;
jsp标签,jstl标签,EL表达式
首先是相关的依赖:
<!-- JSTL表达式的依赖 -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- standard标签库 -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
EL表达式: ${ }
一般用于获取数据,执行计算,获取web开发的常用对象
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>
JSTL表达式:
JSTL标签库的使用就是为了弥补HTML标签的不足,它自定义了许多标签,可以供我们使用,标签的功能和java代码一样
含有格式化标签,sql标签,xml标签,核心标签(掌握)
首先需要导入JSTL核心标签库
<%--首先引入JSTL核心标签库才能使用JSTL标签--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

JSTL标签库的使用只需要引用对应的taglib,然后使用其中的方法
注意在Tomcat也需要引入JSTL的包,否则就会报错:JSTL解析错误
c: if
注意,这里的param是源码中就已经定义好的
取参数的时候直接使用param,参数名称就好
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--首先引入JSTL核心标签库才能使用JSTL标签--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>--%>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>if测试</h3>
<hr>
<form action="coreif.jsp" method="get"> <%--一会自己提交到自己到页面--%>
<%--此处在el表达式中直接输入username是拿不到的
一般EL表达式获取表单中的数据格式为: ${parm.参数名}
--%>
<input type="text" name="username" value="${param.username}">
<input type="submit" value="登录">
</form>
<%--判断 如果提交的用户名是O5,则登录成功--%>
<%
//一般使用Java代码会这么写:
/*if (request.getParameter("username").equals("admain")){
out.print("登陆成功");
}*/
%>
<%--如果使用jstl标签:--%>
<%--首先所有的jstl标签核心库都是以c开头的 xml的需要另外导x的--%>
<%--test是用来比较的,必须要有的,var是用来接收返回值(布尔)的--%>
<c:if test="${param.username=='o5'}" var="isO5" >
<c:out value="欢迎你,尊敬的O5成员"></c:out>
</c:if>
<%--需要一个自闭合标签--%>
<c:out value="${isO5}"></c:out>
</body>
</html>
c:choose c:when
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--首先引入JSTL核心标签库才能使用JSTL标签--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--定义一个成绩变量 值为85--%>
<%--下面的判断跟java一样都是从上到下判断--%>
<c:set var="score" value="20"></c:set>
<c:choose>
<c:when test="${score>=90}">
你的成绩为优秀
</c:when>
<c:when test="${score>=60}">
你的成绩为及格
</c:when>
<c:when test="${score<60}">
你的成绩不及格 重修
</c:when>
</c:choose>
</body>
</html>
c:forEach 注意,c:foreach以后在数据库中会大量用到
创建集合之后想要在进行foreach循环还需要在创建一个list集合进行数据储存,下面的注释说的就是这个
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>foreach</title>
</head>
<body>
<%
ArrayList<String> people = new ArrayList<>();
people.add(0,"亚索");
people.add(1,"劫");
people.add(2,"盲仔");
people.add(3,"钢盆");
// 获取一个资源之后 在请求中创建一个集合(list只是自定义的名字,暂时不确定是否就是一个集合)存起来
request.setAttribute("list",people);
%>
<%--然后通过标签的foreach遍历--%>
<%--
其中var 代表每一次遍历出来的变量
items 代表要遍历的对象
--%>
<c:forEach var="people" items="${list}">
<c:out value="${people}"></c:out>
<br>
</c:forEach>
</br>
<%--还有以下代表for i 循环 从字面意思就很容易理解:开始,结束,和每次的步长(i++)--%>
<%--但是如果不写也是没问题的,begin默认从0开始,end代表最后一个,step默认每次一个--%>
<c:forEach var="people" items="${list}" begin="1" end="3" step="2">
<c:out value="${people}"></c:out>
</c:forEach>
</body>
</html>
javaBean
实体类
javabean有特定的写法:
必须要有一个无参构造
属性必须私有化
必须有对应的get/set方法
一般用来和数据库的字段做映射(ORM)
ORM:对象关系映射
表–>类
字段–>属性
行记录—>对象
people表
| id | name | age | address |
| 1 | 秦疆1号 | 3 | 西安 |
| 2 | 秦疆2号 | 18 | 西安 |
| 3 | 秦疆3号 | 100 | 西安 |
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,"西安");
}
创建一张空表:
id,name,age,address
再创建表的实体类对象,@lombok,有参无参一条龙
实体类测试:
<%@ page import="com.xg.pojo.people" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<% //如果使用java来写:
// people people = new people();
//
// people.setId();
// people.setName();
// people.setAge();
// people.setAddress();
%>
<%-- 下面的代码等价与 people people = new people();--%>
<%--id对应对象的名字 class对应一个类--%>
<jsp:useBean id="people" class="com.xg.pojo.people" scope="page"></jsp:useBean>
<%-- 下面的代码等价于 people.setAddress();--%>
<%-- name对应的就是对象的名字 property对应的就是对象中的变量名 value对应的就是变量的值--%>
<jsp:setProperty name="people" property="id" value="1"></jsp:setProperty>
<jsp:setProperty name="people" property="name" value="xg"></jsp:setProperty>
<jsp:setProperty name="people" property="age" value="22"></jsp:setProperty>
<jsp:setProperty name="people" property="address" value="唐河"></jsp:setProperty>
<%-- 下面的代码等价于 people.getAddress();--%>
ID:<jsp:getProperty name="people" property="id"/>
姓名:<jsp:getProperty name="people" property="name"/>
年龄:<jsp:getProperty name="people" property="age"/>
地址:<jsp:getProperty name="people" property="address"/>
</body>
</html>
Filter过滤器(重点)
filter:过滤器,用来过滤网站的数据
一般用于处理中文乱码,登录验证以及一些其他附加操作

fliter开发步骤:
导包然后编写过滤器

实现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>CharacterEncodingFilter</filter-name>
<filter-class>com.kuang.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<!--只要是 /servlet路径下的任何请求,会经过这个过滤器-->
<url-pattern>/servlet/*</url-pattern>
<!--<url-pattern>/*</url-pattern>-->
</filter-mapping>
监听器
要想使用监听器只需要实现一个监听器的接口,有N种
接下来实际操作一下:
首先编写一个监听器,并实现监听器的接口
//应用:统计网站在线人数 也就是统计session
public class OnlineCountListener implements HttpSessionListener {
//创建session的监听 一旦创建一个session就会触发一个这个事件
public void sessionCreated(HttpSessionEvent se) {
//首先通过getsession后再getServletContext,然后才能往里面传入参数
ServletContext servletContext = se.getSession().getServletContext();
//先getAttribute虚构一个参数名为OnlineCount的OnlineCount参数
Integer onlineCount = (Integer) servletContext.getAttribute("OnlineCount");
//然后再根据条件给参数赋值
if (onlineCount==null){
onlineCount=new Integer(1);//如果人数为null就加一
}else{
int count = onlineCount.intValue();//再将Integer类型的onlineCount转换为int类型并定义为count
onlineCount=new Integer(count++);//如果不等于空创建session的时候就自己加上count(自己加自己)
}
servletContext.setAttribute("onlineCount",onlineCount);//最后将创建好的键值对传入进去
}
//销毁session的监听
//一旦一个session被销毁就会触发一个这个事件
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext servletContext = se.getSession().getServletContext();
Integer onlineCount = (Integer) servletContext.getAttribute("OnlineCount");
if (onlineCount==null){
onlineCount=new Integer(0);//如果人数为null就加一
}else{
int count = onlineCount.intValue();//再将Integer类型的onlineCount转换为int类型并定义为count
onlineCount=new Integer(count-1);//如果不等于空销毁的时候就减去一个
}
servletContext.setAttribute("onlineCount",onlineCount);
}
}
//注意,如果一下同时出来多个,则可能是创建session之后没有链接成功导致没有销毁 又再次创建了,直到链接成功
/*
Session销毁:
1. 手动销毁 getSession().invalidate();
2. 自动销毁 web.xml配置(分钟为单位)
<session-config>
<session-timeout>2</session-timeout>
</session-config>
*/
然后在web.xml中注册一个监听器
<!--注册监听器-->
<listener>
<listener-class>com.kuang.listener.OnlineCountListener</listener-class>
</listener>
最后看情况是否使用
过滤器实操详解:
需求及过程:用户输入密码之后经过过滤器才能进入主页!并且用户在主页注销后就不能进入主页了!
示意图:

首先创建一个主页:
<form action="/login" method="post">
<input type="text" name="username">
<input type="submit">
然后主页输入密码之后跳转到后台页面,并将输入的密码传给后台:
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取前端请求的参数
String username = req.getParameter("username");
System.out.println(username);
if (username.equals("admin")){
//如果确定就把登录信息全部存起来
req.getSession().setAttribute(Constant.USER_SESSION,req.getSession().getId());
resp.sendRedirect("/sys/success.jsp");
}else{
resp.sendRedirect("/error.jsp");
}
}
如果判断密码正确就通过过滤器跳转到主页:
过滤器如下:
过滤器检测session参数是否为空,如果为空就报错
public class sysFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
//注意:此处的ServletRequest 是HttpServletRequest的子类,不能强调,但能强转再调用
HttpServletRequest request= (HttpServletRequest) req;
HttpServletResponse response= (HttpServletResponse) resp;
//过滤器在这里检测request参数是否为空,如果为空就报错
if (request.getSession().getAttribute("USER_SESSION")==null){
//Constant.USER_SESSION是在util包中定义的绝对静态常量,这样如果要修改参数时,方便维护
response.sendRedirect("/error.jsp");
}
chain.doFilter(request,response);
}
public void destroy() {
}
}
session参数不能为空,否则就携带跳到主页:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>欢迎您,尊敬的O5成员</h1>
<a href="/loginout">点击注销</a>
</body>
</html>
在主页可以注销密码,如果点击注销则跳转到如下loginout后端页面:
在LoginOut后端页面中如果参数不为空就用如下方法将参数移除:
req.getSession().removeAttribute(“USER_SESSION”);
public class LoginOutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object user_session = req.getSession().getAttribute("USER_SESSION");//先获取请求携带的参数
if (user_session!=null){
//参数不为空就移除参数
req.getSession().removeAttribute("USER_SESSION");
resp.sendRedirect("/Login.jsp");
}else{
//如果正常登录就绝对有参数,没有参数则说明跳过了初始页面的登录步骤
//而是直接点开了成功页面的跳转链接
//这肯定是不允许的,所以要跳转到报错页面
resp.sendRedirect("/error.jsp");
}
}
如果密码错误就跳转到报错页面:
<html>
<head>
<title>错误</title>
</head>
<body>
<h1>密码错误,请求失败</h1>
<a href="Login.jsp">点击回到验证页面</a>
</body>
</html>
JDBC
什么是JDBC:jdbc就是java连接数据库

首先需要jar包的支持:
java.sql javax.sql,mysql-conneter-java…连接驱动(必须要导入)
实验环境搭建
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;
导入数据库依赖
<!--mysql的驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
IDEA中连接数据库:

JDBC 固定步骤:
- 加载驱动
- 连接数据库,代表数据库
- 向数据库发送SQL的对象Statement : CRUD
- 编写SQL (根据业务,不同的SQL)
- 执行SQL
- 关闭连接
如下为执行查询语句的方法:
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="981216";
// 1,加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.链接数据库 connection即代表数据库本身
Connection connection = DriverManager.getConnection(url, username, password);
//3,向数据库发送sql对象的是Statement 用它才能执行CRUD
//preparedStatement更安全
Statement statement = connection.createStatement();
//4,编写sql
String sql="SELECT * FROM users";
//5.执行查询sql,只有查询才会返回resultset结果集,其他都是返回int(受影响的行数)
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 updatejdbc {
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="981216";
// 1,加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.链接数据库 connection即代表数据库本身
Connection connection = DriverManager.getConnection(url, username, password);
//3,向数据库发送sql对象的是Statement 用它才能执行CRUD
Statement statement = connection.createStatement();
//4,编写sql
String sql="delete from users where id=3";
//5.执行sql,增删改都使用的executeUpdate返回int(受影响的行数)
int i=statement.executeUpdate(sql);
if (i==0){ //受影响的行数为0就肯定是执行失败
System.out.println("执行失败或条件不符合");
}else{
System.out.println("sql语句执行成功");
}
//6,关闭连接,释放资源 (必须要做)
statement.close();
connection.close();
}
}
预编译SQL (就是为了解决sql注入问题,同时也方便进行参数更换)
public class PreparedStatement {
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="981216";
// 1,加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.链接数据库 connection即代表数据库本身
Connection connection = DriverManager.getConnection(url, username, password);
//3,编写sql
String sql="insert into users(id,name,password,email,birthday)values (?,?,?,?,?)";
//4,预编译
java.sql.PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,3);//给第一个占位符的?赋值为1
preparedStatement.setString(2,"亚索");//给第二个占位符?赋值为亚索
preparedStatement.setString(3,"981216");
preparedStatement.setString(4,"xg@qq.com");
preparedStatement.setDate(5,new Date(new java.util.Date().getTime()));
//5,执行sql
int i = preparedStatement.executeUpdate();
if (i==0){ //受影响的行数为0就肯定是执行失败
System.out.println("执行失败或条件不符合");
}else{
System.out.println("sql语句执行成功");
}
//6,关闭连接,释放资源 (必须要做)
preparedStatement.close();
connection.close();
}
}
事务:
事务就是在多段sql语句执行前后要么都成功,要么都失败
ACID原则:保证数据的安全。
开启事务
事务提交 commit()
事务回滚 rollback()
关闭事务
转账:
A:1000
B:1000
A(900) --100--> B(1100)
事务回顾:
一定要设置 connection.setAutoCommit(false);//设置为false代表默认操作失败,true是默认操作成功
如果设置为false代表默认执行成功,也就会导致回滚失败
public class 事务 {
Connection connection=null;
@Test
public void test() throws SQLException {
//配置信息
//useUnicode=true&characterEncoding=utf-8 用于解决中文乱码问题
String url="jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String username="root";
String password="981216";
// 1,加载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
//2.链接数据库 connection即代表数据库本身
connection = DriverManager.getConnection(url, username, password);
//3.通知数据库开启事务
connection.setAutoCommit(false);//设置为false是开启,true是关闭
String sql="update account set money=money+200 where id=1";
connection.prepareStatement(sql).executeUpdate();
//4,手动制造错误
//int a=1/0;
String sql2="update account set money=money-100 where id=2";
connection.prepareStatement(sql2).executeUpdate();
connection.commit();
System.out.println("程序执行成功");
} catch (ClassNotFoundException e) {
e.printStackTrace();
//如果出现异常就通知数据库回滚异常
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
connection.rollback();
}finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
功能扩展
文件上传
首先需要两个jar包(此处是不配置maven直接下载后手动导包的)

PS:没有maven时导包:

文件上传优化事项(面试会问)
- 为了保证服务器安全,上传文件应该f昂在外界无法直接访问的目录下面,如WEB-INF目录中
- 为了防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名,比如通过添加后缀,时间戳,uuid(产生唯一id),md5加密,或者其他位运算,算法之类
- 需要限制上传文件的最大值,因为会占用服务器资源
- 限制上传文件的类型,在收到上传文件名时,判断是否合法(同样是为了节省服务器资源)
文件上传需要用到的类详解:
//ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项目封装成一个FileItem对象,
// 在使用ServletFileUpload对象进行解析请求时 需要DiskFileItemFactory对象
//所以我们在进行解析工作前构造好DiskFileItemFactory对象
//通过ServletFileUpload对象的而构造方法或者setFileItemFactory()方法设置ServletFileUpload对象的FileItemFactory属性
表单如果包含一个文件上传输入项的话,这个表单的enctype属性就必须设置为multipart/form-data
ServletFileUpload类
ServletFileUpload负责处理上传的文件数据,并将表中每一个输入项封装在一个FileItem对象中,使用其parseRequest(就是HttpServletRequest)方法可以将通过表单中每一个HTML标签提交的数据封装成一个FileItem对象,然后以List列表的形式返回,使用该方法处理上传文件简单易用

被折叠的 条评论
为什么被折叠?



