会话跟踪
- 常用的会话跟踪技术是cookie和session,保证用户在会话期间的数据管理
cookie
- cookie会在本地记录信息,不安全
- 设置cookie,在业务类中(因为路由先到这,再返回页面)
Cookie cookie = new Cookie("jieguo","true"); response.addCookie(cookie);
- 这个可以在浏览器查看到,属于客户端行为
- 服务端获取客户端携带的cookie,验证并返回页面
<% Cookie[] cookies = request.getCookies(); if(cookies != null) for(Cookie c : cookies){ String name = c.getName();//获取Cookie名称 if("jieguo".equals(name)){ String value = c.getValue();//获取Cookie的值 bool = Boolean.valueOf(value);//将值转为Boolean类型 } } %>
- 删除cookie
//1.创建⼀个name为username的Cookie Cookie cookie = new Cookie("username", "aaa"); //2.设置Cookie的有效时间为0 cookie.setMaxAge(0);//删除cookie的关键 //3.将cookie发送给浏览器,来替换同名Cookie response.addCookie(cookie);
- 注:以上演示都是在服务器,客户端(浏览器)有默认的保存cookie的行为
session
- session的内容会存在服务器,比较安全,但占用空间(session⾥的信息应该尽量精简)
- 一般登录成功后会在session存储用户名密码等,在同一个浏览器的不同请求都可以获取已登录状态
- 同样可以设置过期时间
HttpSession session = request.getSession(); // 获取Session对象 session.setAttribute("loginTime", new Date()); // 设置Session中的属性 out.println("登录时间为:" +(Date)session.getAttribute("loginTime")); // 获取Session属性 // 过期时间 session.setMaxInactiveInterval(longinterval) // 分钟 // 也可以在web.xml设置 <session-config> <session-timeout>30</session-timeout> </session-config>
- 设置失效
session.invalidate()
- cookie 一般保存的是
session ID
,通过ID确定session信息后即可保持登录状态、获取相关数据
filter
- 过滤器实际上就是对web资源进⾏拦截,做⼀些处理后再交给下⼀个过滤器或servlet处理
- 例如大部分页面都需要登录后访问,可以添加过滤器验证
// 新建util.FilterTest.java public class FilterTest implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("初始化filter"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("begin filter"); filterChain.doFilter(servletRequest, servletResponse); System.out.println("end filter"); } @Override public void destroy() { System.out.println("destroy filter"); } }
- web.xml中也要配置
<filter> <filter-name>过滤器名称</filter-name> <filter-class>过滤器所在的路径</filter-class> </filter> <filter-mapping> <filter-name>过滤器名称</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
- 如果有多个过滤器,都需要在xml配置,走完过滤器才会走servlet
- 如果路径表达式使用
/*
,所有请求都会走这个过滤器@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("begin filter"); HttpServletRequest request = (HttpServletRequest)servletRequest; HttpServletResponse response = (HttpServletResponse)servletResponse; // 限制登录 String requestURI = request.getRequestURI(); Object username = request.getSession().getAttribute("username"); if (requestURI.endsWith("testfilter.jsp") && username==null) { response.sendRedirect("login.jsp"); } filterChain.doFilter(servletRequest, servletResponse); System.out.println("end filter"); }
- request和response时的过滤器执行顺序是相反的
- 除了验证登录,还常用在
- .设置编码⽅式–统⼀设置编码
- 加密解密(密码的加密和解密)
- 下载资源的限制
listener
- 监听器会监听某个域对象的的状态的变化,我们一般监听session作用域
- 监听器的相关概念:
- 事件源:被监听的对象(三个域对象 request、session、servletContext)
- 监听器:监听事件源对象事件源对象的状态的变化都会触发监听器
- 注册监听器:将监听器与事件源进⾏绑定
- 响应⾏为:监听器监听到事件源的状态变化时所涉及的功能代码(程序员编写代码)
- 可以按照被监听的对象划分
- ServletRequest域、HttpSession域、ServletContext域
- 也可以按照监听的内容划分
- 对象的创建和销毁,属性的变化
- 自定义实现监听器
编写⼀个监听器类去实现监听器接⼝ 覆盖监听器的⽅法 需要在web.xml中进⾏配置—注册
- 框架里很多自动化的操作都是通过监听器实现的
MVC
- 为了让后台杂乱无章的代码有迹可循,出现了MVC设计模式,解耦代码
- 三层架构
- 通常意义上的三层架构就是将整个业务应⽤划分为:表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)
- 以BLL为核心,可以理解为是之前讲的xml路由映射和Servlet方法
- 三层是基于业务逻辑来分的,⽽MVC是基于⻚⾯来分的
- MVC把三层架构中的UI层再度进⾏了分化
- 三层架构的分层模式是典型的上下关系,上层依赖于下层。但MVC作为表现模式是不存在上下关系的
model
- 建立项目,结构如下,引入jar包
- 代码从bean开始写,执行从servlet开始
- 建表,建实体类(模型类)
DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `studentid` int(11) NOT NULL AUTO_INCREMENT, `studentno` varchar(20) DEFAULT NULL, `stuname` varchar(5) DEFAULT NULL, `stuage` int(11) DEFAULT NULL, `gradeid` int(11) DEFAULT NULL, PRIMARY KEY (`studentid`) ) ENGINE=InnoDB AUTO_INCREMENT=122 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of student -- ---------------------------- INSERT INTO `student` VALUES ('1', 's1101', '张三', '11', '1'); INSERT INTO `student` VALUES ('2', 's1102', '李四', '22', '1'); INSERT INTO `student` VALUES ('3', 's1103', '王五', '33', '1'); INSERT INTO `student` VALUES ('4', 's1104', '赵柳', '44', '2'); INSERT INTO `student` VALUES ('5', 's1105', '田七', '55', '2'); INSERT INTO `student` VALUES ('110', 's110', 'abc', '66', '2'); INSERT INTO `student` VALUES ('111', 's111', '谢大脚1', '77', '2'); INSERT INTO `student` VALUES ('112', 'sno110', '广坤', '88', '2'); INSERT INTO `student` VALUES ('113', 'sno11', '谢广坤', '99', '3'); INSERT INTO `student` VALUES ('114', 'sno001', '广坤1', '1', '3'); INSERT INTO `student` VALUES ('115', 's00111', '谢大脚2', '2', '3'); INSERT INTO `student` VALUES ('116', 's00113', '谢大脚3', '3', '3'); INSERT INTO `student` VALUES ('117', 's00114', '谢大脚4', '4', '3'); INSERT INTO `student` VALUES ('120', 'a1101', '张娜', '18', null); INSERT INTO `student` VALUES ('121', 'c101', '广坤', '50', null);
package xzk.bean; public class Student { private Integer studentid; private String studentno; private String stuname; private Integer stuage; private Integer gradeid; // 构造 public Student() { } public Student(Integer studentid, String studentno, String stuname, Integer stuage, Integer gradeid) { this.studentid = studentid; this.studentno = studentno; this.stuname = stuname; this.stuage = stuage; this.gradeid = gradeid; } // get set public Integer getStudentid() { return studentid; } public void setStudentid(Integer studentid) { this.studentid = studentid; } public String getStudentno() { return studentno; } public void setStudentno(String studentno) { this.studentno = studentno; } public String getStuname() { return stuname; } public void setStuname(String stuname) { this.stuname = stuname; } public Integer getStuage() { return stuage; } public void setStuage(Integer stuage) { this.stuage = stuage; } public Integer getGradeid() { return gradeid; } public void setGradeid(Integer gradeid) { this.gradeid = gradeid; } }
- dao层定义操作数据库接口并实现
package xzk.dao; import xzk.bean.Student; import java.util.List; // 操作bean的接口 public interface StudentDao { public List<Student> getStudents(); }
public class StudentDaoImpl extends DruidUtil implements StudentDao { @Override public List<Student> getStudents() { List list = new ArrayList(); Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { connection = getConnection(); preparedStatement = connection.prepareStatement("select * from student"); resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { Student student = new Student(); student.setStudentid(resultSet.getInt("studentid")); student.setStudentno(resultSet.getString("studentno")); student.setStuname(resultSet.getString("stuname")); student.setStuage(resultSet.getInt("stuage")); student.setGradeid(resultSet.getInt("gradeid")); list.add(student); } return list; } catch (SQLException e) { e.printStackTrace(); } finally { close(connection, preparedStatement, resultSet); } return null; } }
- 为此需要引入工具类Druid和配置文件
package xzk.util; import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import javax.xml.transform.Result; import java.io.IOException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; public class DruidUtil { private static DataSource ds; static{ try { Properties ppt = new Properties(); ppt.load(DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties")); ds = DruidDataSourceFactory.createDataSource(ppt); } catch (Exception e) { e.printStackTrace(); } } /** * 从连接池中取出一个连接给用户 * @return */ public static Connection getConnection(){ try { return ds.getConnection(); } catch (SQLException throwables) { throwables.printStackTrace(); } return null; } public static void close(Connection conn, Statement state, ResultSet rs){ try { rs.close(); } catch (Exception throwables) { throwables.printStackTrace(); } try { state.close(); } catch (Exception throwables) { throwables.printStackTrace(); } try { conn.close(); } catch (Exception throwables) { throwables.printStackTrace(); } } }
// druid.properties url=jdbc:mysql://localhost:3306/mvc?useUnicode=true&characterEncoding=utf-8 username=root password=123456 driverClassName=com.mysql.cj.jdbc.Driver initialSize=5 maxActive=10 minIdle=5 maxWait=3000
controller
- service层定义业务逻辑,接口名称:bean+Service
// 定义业务逻辑 // 这里就是简单调用一下dao层的实现 public interface StudentService { public List<Student> getAll(); } public class StudentServiceImpl implements StudentService { private StudentDao studentDao = new StudentDaoImpl(); @Override public List<Student> getAll() { return studentDao.getStudents(); } }
- servlet调用service层的代码
// 相当于 Controller 管理路由+限定请求方法+调用业务类+返回页面 @WebServlet(urlPatterns = "/getstuall") public class StudentServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 1 接受请求参数 // 2 调取service层方法 StudentServiceImpl studentService = new StudentServiceImpl(); List<Student> all = studentService.getAll(); // 3 跳转页面 req.setAttribute("slist", all); req.getRequestDispatcher("/show.jsp").forward(req, resp); // req存的值作用域是单次请求,只能dispatcher } }
- 可以启动了,注意Druid配置文件的路径,可能要改为相对路径
前后端分离
- 以公共接口为桥梁
AJAX
- AJAX = Asynchronous JavaScript and XML
- 在不重新加载整个⻚⾯的情况下,AJAX 与服务器交换数据并更新部分⽹⻚
- 是⼏种原有技术的结合体
- 使⽤CSS和XHTML来表示
- 使⽤DOM模型来交互和动态显示
- 使⽤XMLHttpRequest来和服务器进⾏异步通信
- 使⽤javascript来绑定和调⽤
- AJAX 的核⼼是
XMLHttpRequest
对象,发送异步请求
工作原理
- 相当于在⽤户和服务器之间加了—个中间层(AJAX引擎),使⽤户请求与服务器响应异步
化
- 普通的交互方式:发出请求,等待服务器回复
- ajax交互方式:JavaScript发出请求,不必等待,可以继续发出请求
- 并不是所有的⽤户请求都提交给服务器
- —些数据验证和数据处理等都交给Ajax引擎⾃⼰来做(异步)
- 确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求
- 案例:验证用户名有效性
<%-- Created by IntelliJ IDEA. User: Windows10 Date: 2021/12/31 Time: 20:46 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>ajax</title> </head> <script type="text/javascript"> function test(){ // 发送异步请求 // 1. 创建XMLHttpRequest对象 var xmlhttp; if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); }else if (window.ActiveXObject) { // IE浏览器 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP") } // 2. 打开链接 (从前到后 servlet) var username = document.getElementById("uname").value; xmlhttp.open("get", "/test?username="+username, true); // 3. 指定回调函数 (从后到前) xmlhttp.onreadystatechange=function () { // 判断状态(会监听) if (xmlhttp.readyState == 4) { // 接受input输入的数据 var response = xmlhttp.responseText; // 放到指定位置 document.getElementById("rs").innerText=response; } } // 4. 发送数据 (展示) xmlhttp.send(); } </script> <body> <h1>username test</h1> username: <input type="text" id="uname" onblur="test()"><span id="rs"></span> </body> </html>
@WebServlet(urlPatterns = "/test") public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 接收参数 String username = req.getParameter("username"); resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); if ("admin".equals(username)) { writer.println("账户已被注册"); }else { writer.println("账户名可用"); } } }
- 只能新建项目,不能和上一节的xzk目录并行
- span里还是不显示中文,只有???
属性和方法
- 都是基于
XMLHttpRequest
- 主要介绍
readyState
,存有服务器响应的状态信息,每当 readyState 改变时,onreadystatechange
函数就会被执⾏,这个回调是异步的基础,可以了解一下
open()
,第⼀个参数定义发送请求所使⽤的⽅法,第⼆个参数规定服务器端脚本的URL,第
三个参数规定应当对请求进⾏异步地处理send()
⽅法将请求送往服务器,(从前到后,open就是个准备,还需send执行)xmlHttp.open("GET", "/test?username="+username, true); xmlHttp.send(null); // 如果是get xmlHttp.open("POST","test.php",true); var params = "userName=" + uname+ "&userPass=" +upass+ "&time=" +Math.random(); // 增加time随机参数,防⽌读取缓存 xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded;charset=UTF-8"); // 向请求添加 HTTP 头,POST如果有数据⼀定加加!!!! xmlHttp.send(params);
- get 还是 post?
- 异步还是同步
jQuery
- jQuery实现AJAX
# jquery_ajax.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>jquery</title> </head> <script type="text/javascript" src="js/jquery-1.8.0.min.js"></script> <script type="text/javascript"> $(function () { $("#uname").blur(function () { // 失去焦点 // 获取前端输入框 value 值 var uname = $(this).val(); // 发送请求 (从前到后) $.ajax({ // 无需创建XMLHttpRequest对象 url:"testjq", data:"username="+uname, type:"post", dataType:"text", success:function (rs) { // 自动判断状态 (从后到前,不需要responseText) $("#rs").html(rs); } }) //个get请求的简单写法 // $.get("/testjq", "uaername="+uname, function (rs) { // span id // $("#rs").html(rs) // }) // post提交的简单写法 // $.post("/testjq", "uaername="+uname, function (rs) { // span id // $("#rs").html(rs) // }) }) }) </script> <body> <h1>jQuery ajax test</h1> username: <input type="text" id="uname" onblur="test()"><span id="rs"></span> </body> </html>
- 后端路由需要改一下,servlet处理方法不变
- 后端路由需要改一下,servlet处理方法不变
- 拿捏住,ajax 就是用已有组件、由前端发起的、在BS中间插了一杠子的异步请求方式
json
- 传数据呀,传字符串或者xml都过时了,还是要用json
- JSON (JavaScript Object Notation) 是⼀种轻量级的数据交换格式
- 大致看一下定义和取值
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>json</title> </head> <script type="text/javascript"> var js = {"name":"roy", "age":18}; alert(js.name); var ja = {"name":["roy","allen"]}; alert(ja.name[0]); </script> <body> </body> </html>
- 转换,依赖 json-lib-2.2.2-jdk15.jar,scope=compile即可
package tajax; public class User { private String name; private Integer age; public User() { } public User(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
public class UserTest { public static void main(String[] args) { User user = new User("roy", 11); // java -> json JSONObject jsonObject = JSONObject.fromObject(user); System.out.println(jsonObject); // json -> java String str = "{\"age\":11,\"name\":\"roy\"}"; JSONObject jsonObject1 = JSONObject.fromObject(str); Object bean = JSONObject.toBean(jsonObject1, User.class); System.out.println(bean); // User{name='roy', age=11} // 集合也是类似的 } }
- 更新页面只需要Update classes…,更改类需要Restart
- 案例:json+ajax 实现输入用户id自动填充信息
- 之前设置了jar包compile(需要provided),所以访问页面可能会找不到jar包
- 可以直接放到tomcat的lib里,删除out重启;或者删除lib重新Modules
- 后端返回后,还会涉及到一个
eval("("rs")")