1、CGLIB代理
有一个类没有实现接口,想要对这个类实现增强,就需要使用CGLIB代理
- 导入CGLIB的包
cglib
cglib
3.3.0
- 编写被代理的类
package com.wz.practice.proxy.cglib;
public class UserService {
public void add(){
System.out.println("--------add执行--------");
}
public void update(){
System.out.println("--------update执行--------");
}
}
- 实现代理
package com.wz.practice.proxy.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 实现了MethodInterceptor接口:该接口是CGLIB提供的用于连接方法调用的机制
* 通过实现intercept方法,可以在方法调用前后进行额外的操作.
*/
public class UserServiceFactory implements MethodInterceptor {
private UserService userService;
public UserServiceFactory(UserService userService){
this.userService=userService;
}
public UserService getUserServiceProxy(){
//创建Enhancer对象,
Enhancer enhancer = new Enhancer();
//给生成的类指定一个爹
enhancer.setSuperclass(UserService.class);
//将UserServiceFactory设置为方法拦截器callback
enhancer.setCallback(this);
//创建代理对象,将其转换为UserService并返回
return (UserService) enhancer.create();
}
/**
*在这里进行拦截
* @param o
* @param method
* @param objects
* @param methodProxy
* @return
* @throws Throwable
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("打开事务");
//method.invoke() 方法是 Java 反射 API 提供的方法,
// 用于在指定对象上调用指定的方法。
// 它接受两个参数:第一个参数是要调用方法的对象实例,第二个参数是要传递给方法的参数。
Object invoke = method.invoke(this.userService, objects);
System.out.println("提交事务");
return invoke;
}
}
- 测试
package com.wz.practice.proxy.cglib;
public class Test001 {
public static void main(String[] args) {
UserService userServiceFactory = new UserServiceFactory(new UserService()).getUserServiceProxy();
userServiceFactory.add();
}
}
结果:
2、jsp是什么
jsp的爹是 HttpJspbase HttpJspBase 继承了 HttpServlet
也就是说 jsp本质就是一个Servlet
jsp的对外表象就是一个页面,但是这个页面上可以完成Servlet的所有功能
jsp是不能直接运行的,在运行之前需要先经过翻译这样一个过程,翻译成Java代码之后,在编译成.class文件 最终这个class文件才会运行
3、域对象
拥有作用域的对象称为域对象,简单来说就是有作用范围的Java对象
jsp中有四个域对象
request:作用范围是当前请求,当前请求结束,这个域对象就不存在了,每一个请求都会创建你这样一个域对象。
session:生命周期是当前会话 (简单理解就是一次浏览器的打开和关闭)实际上会话的生命周期是30分钟,即使页面关闭了,这个对象也会在jvm中存活一定时间才会死亡
application(ServletContext):Tomcat只要打开这个对象就存在,tomcat关闭这个对象就不存,生命周期最长
pageContext:生命周期是当前页面,页面关闭,这个对象就不存在了
按照生命周期先后顺序排序:
pageContext < request < session < application(ServletContext)
在开发中使用的最多的是 request session也有使用 application和pageContext基本不会使用
与域对象究竟有啥作用呢?
可以将Servlet的执行结果直接 带到jsp页面并进行显示
4、EL表达式
EL表达式能直接从四个域对象中取出数据
4.1、El表达式的基本使用
4.1.1、在Servlet中向域对象放数据
package com.wz.practice.servlet;
import com.wz.practice.pojo.User;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
@WebServlet(urlPatterns = "/users")
public class UserServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//这里可以向域对象里放数据
req.setAttribute("username","ZhangSan");
req.setAttribute("user",new User(01,"ZhangSan","123456"));
ArrayList userList = new ArrayList();
for (int i = 0; i < 3; i++) {
userList.add(new User(i+1,"Username"+i,"123456"));
}
req.setAttribute("list",userList);
//在session对象中放数据
HttpSession session = req.getSession();
session.setAttribute("sessionKey","sessionVal");
//在application中放对象
ServletContext application = req.getServletContext();
application.setAttribute("applicationKey","applicationVal");
req.getRequestDispatcher("/index.jsp").forward(req,resp);
}
}
4.1.2、在页面上使用EL表达式取数据
<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
Title
<%
pageContext.setAttribute("pageKey","pageVal");
%>
<%--从req中取数据--%>
用户名是:${username}
对象的名字:${user.username}
集合中第一个对象的名字:${list[0].username}
<%--从session中取数据--%>
从session中取数据:${sessionKey}
从application中取数据:${applicationKey}
从pageContext中取数据:${pageKey}
结果:
4.2、EL取出数据的顺序
pageContext < req < session < application
上面的顺序就是我们的EL表达式取出数据的顺序
如果是pageContext没取到 那么就会去 req中取数据 req中没取到 那么就要去session中取数据 session中没取
到 那么就要去application中取出数据
EL表达式 只能 取出数据 不能表达逻辑关系 以及遍历集合
5、JSTL标准标签库的基本使用
JavaServer Pages Standard Tag Library
EL存在的问题:
- EL主要用于作用域获取数据,虽然可以做判断,但是得到的都是一个结果做展示
- EL不存在流程控制语句,比如判断
- EL对于集合只能做单点访问,不能实现遍历操作,比如循环
JSTL是一个jsp的标签集合
JSTL的作用:
可以对EL获取到的数据进行逻辑操作
可以与EL合作完成数据的展示
- 导包
javax.servlet
jstl
1.2
- 数据准备
package com.wz.practice.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
private Integer id;
private String username;
private Double salary;
}
package com.wz.practice.servlet;
import com.wz.practice.pojo.Dept;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
@WebServlet(urlPatterns = "/depts")
public class DeptServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("age",18);
req.setAttribute("score",10);
ArrayList depts = new ArrayList();
for (int i = 0; i < 10; i++) {
depts.add(new Dept(i+1,"clerk"+i+1,8000.));
}
req.setAttribute("deptList",depts);
req.getRequestDispatcher("/dept_list.jsp").forward(req,resp);
}
}
- 取数据
<%--
Created by IntelliJ IDEA.
User: WangZhi
Date: 2023/8/19
Time: 11:37
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%--prefix标签库的前缀--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Title
<%--jstl中的逻辑运行算符--%>
电影可看
<%--if-----else if---else--%>
不及格
良好
优秀
id
名称
工资
遍历下标
<%--
items:遍历的集合是啥
var:每一次遍历出来的对象是啥
varStatus:每一次遍历的状态
begin="起始下标" 不写
end="结束下标" 不写
step="间隔长度" 不写
--%>
${dept.id}
${dept.username}
${dept.salary}
${status.index}
结果: