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 固定步骤:

  1. 加载驱动
  2. 连接数据库,代表数据库
  3. 向数据库发送SQL的对象Statement : CRUD
  4. 编写SQL (根据业务,不同的SQL)
  5. 执行SQL
  6. 关闭连接
    如下为执行查询语句的方法:
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列表的形式返回,使用该方法处理上传文件简单易用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值