练习
- 一、redis实现分页思想
- 二、EL表达式拿值
- 三、自己实现一个ArrayList
- 四、异常体系
- 五、内部类
- 六、Mybatis二级缓存
- 七、动态代理
- 八、反射
- 九、打代码中遇到的问题
- 在自己做VUE和ELEMENT结合ajax实现前后端登录和数据的增删改查
- 3.数据库字段和类属性
- 4.数据库中double类型和idea中double类型代表的存储占用空间不一样,要小心
- 5.html中表单提交页面交互会有BUG,要用ajax技术来实现异步的前后端交互
- 6.Dao层的interface和mapper映射文件
- 7.属性和数据库的字段名 匹配
- 8. MAVEN中如果都是好的,要打包不行,看下配置的时候是war还是jar
- 9. Error querying database. Cause: java.sql.SQLException: Must specify port after ':' in connection string
- Process finished with exit code -1073741819 (0xC0000005) 和解决maven编译 Process terminated
- 十、系统监控功能
一、redis实现分页思想
题目:
redis中有String hash list set数据结构,用一个或多个数据结构,实现页面中的前进和后退
实现思路:用两个list分别存储页面的前进和后退
实现具体流程和讲解
二、EL表达式拿值
三、自己实现一个ArrayList
主要是扩容时间比较重要
package ybb;
import java.util.Arrays;
public class YbbArraylist<E> {
//定义初始默认容量
private static final int DEFAULT_CAPACITY = 10;
//定义初始空数组
private static final Object[] EMPTY = {};
//成员属性
transient Object[] elementData={};
private int size;
//定义极限数组大小
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//构造方法
public void ybbArraylist() {
this.elementData = EMPTY;
}
public void ybbArraylist(int number) {
if (number > 0) {
//定义长度
this.elementData = new Object[number];
} else if (number == 0) {
this.elementData = EMPTY;
} else {
throw new RuntimeException("请输入数字啊,你这输入的我不知道怎么初始创建了");
}
}
public boolean add(E e) {
int num= check(size + 1);//检查下能不能加入,或者扩容
if (elementData.length<num){
grow(num);
}
elementData[size] = e;
size++;
return true;
}
private void grow(int checkSize) {
int oldSize=elementData.length;
int newSize = oldSize + (oldSize>> 1);
if (newSize - checkSize < 0 ) {
newSize=checkSize;
}
if (newSize-MAX_ARRAY_SIZE>0){
if (checkSize>MAX_ARRAY_SIZE){
checkSize=Integer.MAX_VALUE;
}else {
checkSize=MAX_ARRAY_SIZE;
}
}
elementData = Arrays.copyOf(elementData, newSize);
}
private int check(int checkSize) {
//判断是否为空
if (Arrays.equals(elementData,EMPTY)) {
return Math.max(DEFAULT_CAPACITY, checkSize);
}
return checkSize;
}
public E get(int index) {
if (index > elementData.length) {
throw new RuntimeException("越界了呀,瓜皮");
} else {
return (E) elementData[index];
}
}
public E set(int index, E element) {
if (index > elementData.length) {
throw new RuntimeException("找不到怎么修改啊,瓜皮");
} else {
E oldElement = element;
elementData[index] = element;
//修改后,返回修改前的数据,可以做比较
return oldElement;
}
}
public E remove(int index) {
if (index > elementData.length) {
throw new RuntimeException("找不到怎么修改啊,瓜皮");
} else {
E oldElement = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0) {
//原目标数组 从原数据的xx位置开始 目标数组 目标数组的xx位置开始 要copy的长度
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
}
elementData[--size] = null;//删完置为空
return oldElement;
}
}
public int length(){
return size;
}
}
四、异常体系
Throwable是所有异常的超类
Error 错误
不应该视图捕获的严重异常
一般是发生严重故障时,堆内存溢出,绝症,在java程序处理的范畴之外
Exception 异常
IOException(I/O输入输出异常)(受查异常)
编译期间必须得到处理的异常
例如格式化异常
RuntimeException(运行时异常)(非受查异常)
编译通过,运行时会报错
例如 最经典的数组索引越界异常
处理方式
一:throws/throw关键字
throws关键字声明,放在方法的尾部
或者
throw new 异常类名(参数)
二:try…catch关键字 (捕获异常)
try{
正常运行的代码
}catch(ExceptionName e1){
出现问题后执行的代码,多用于抛出
}finally{
无论发生异常,最终都会执行的代码,多用于关闭资源
}
public static void main(String[] args){
int result = test3();
System.out.println(result);
}
public static int test3(){
//try 语句块中有 return 语句时的整体执行顺序
int i = 1;
try{
i++;
System.out.println("try block, i = "+i);
return i;
}catch(Exception e){
i ++;
System.out.println("catch block i = "+i);
return i;
}finally{
i = 10;
System.out.println("finally block i = "+i);
}
}
输出结果如下:
try block, i = 2
finally block i = 10
2
是不是有点疑惑?明明我 try 语句块中有 return 语句,可为什么最终还是执行了 finally 块中的代码?
我们反编译这个类,看看这个 test3 方法编译后的字节码的实现:
0: iconst_1 //将 1 加载进操作数栈
1: istore_0 //将操作数栈 0 位置的元素存进局部变量表
2: iinc 0, 1 //将局部变量表 0 位置的元素直接加一(i=2)
5: getstatic #3 // 5-27 行执行的 println 方法
8: new #5
11: dup
12: invokespecial #6
15: ldc #7
17: invokevirtual #8
20: iload_0
21: invokevirtual #9 24: invokevirtual #10
27: invokevirtual #11
30: iload_0 //将局部变量表 0 位置的元素加载进操作栈(2)
31: istore_1 //把操作栈顶的元素存入局部变量表位置 1 处
32: bipush 10 //加载一个常量到操作栈(10)
34: istore_0 //将 10 存入局部变量表 0 处
35: getstatic #3 //35-57 行执行 finally中的println方法
38: new #5
41: dup
42: invokespecial #6
45: ldc #12
47: invokevirtual #8
50: iload_0
51: invokevirtual #9
54: invokevirtual #10
57: invokevirtual #11
60: iload_1 //将局部变量表 1 位置的元素加载进操作栈(2)
61: ireturn //将操作栈顶元素返回(2)
-------------------try + finally 结束 ------------
------------------下面是 catch + finally,类似的 ------------
62: astore_1
63: iinc 0, 1
.......
.......
从我们的分析中可以看出来,finally 代码块中的内容始终会被执行,无论程序是否出现异常的原因就是,编译器会将 finally 块中的代码复制两份并分别添加在 try 和 catch 的后面。
可能有人会所疑惑,原本我们的 i 就被存储在局部变量表 0 位置,而最后 finally 中的代码也的确将 slot 0 位置填充了数值 10,可为什么最后程序依然返回的数值 2 呢?
仔细看字节码,你会发现在 return 语句返回之前,虚拟机会将待返回的值压入操作数栈,等待返回,即使 finally 语句块对 i 进行了修改,但是待返回的值已经确实的存在于操作数栈中了,所以不会影响程序返回结果。
finally中多个retrun的话会产生覆盖
作者:凯玲之恋
链接:https://www.jianshu.com/p/49d2c3975c56
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
五、内部类
可以将一个类的定义放在另一个类的定义内部。这就是内部类
成员内部类
一个类的定义放在另一个类的定义内部
1.可以无条件的访问外部类的所有的成员属性,不受private和static影响
2.当内部类和外部类有方法或者属性同名的时候,在怎么调用,在内部类中调用的是自己的,调用外部类 “外部类”.this.成员变量/成员方法
3.如果外部类想访问内部类,要先生成内部类对象,才能访问
4.内部类是依附在外部类中的,如果在其他类中想访问内部类,需要先创建内部类
class Circle {
double radius = 0;
public Circle(double radius) {
this.radius = radius;
}
class Draw { //内部类
public void drawSahpe() {
System.out.println("drawshape");
}
}
}
局部内部类
局部内部类主要是根据内部类定义的作用域来区分的,定义在一个方法或者某个作用域内的类
和局部变量一样,不能访问权限修饰符关键字
作用区间只能在申明的局部内
class People{
public People() {
}
}
class Man{
public Man(){
}
public People getWoman(){
class Woman extends People{ //局部内部类
int age =0;
}
return new Woman();
}
}
匿名内部类
没有名称的内部类
一般用于继承其他类或者是实现接口,并不缺需要增加额外的方法,只对继承方法的实现或是重写
编写代码时用的最多的,在编写事件监听的代码时使用不但方便而且更容易维护
不能使用static和权限修饰符
没有构造器,通过new XXX的方式生成一个对象的引用
匿名内部类属于局部内部类,和上面限制一样
静态内部类
多个static关键字,不需要依赖 外部类
但也必须依附于具体的对象访问
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
}
}
class Outter {
public Outter() {
}
static class Inner {
public Inner() {
}
}
}
六、Mybatis二级缓存
一级缓存是SqlSession级别的缓存。操作数据库的时候需要构造sqlsession对象来调用对应的方法
二级缓存是Mapper级别 多个SqlSession去操作同一个Mapper的sql语句(共享)
一级缓存是默认开启的
二级缓存需要手动开启
<!-- 全局参数的配置 -->
<settings>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
缓存数据失效时机
在表的结构或数据发生改变时,查询缓存中的数据不再有效。有这些INSERT、UPDATE、 DELETE、TRUNCATE、ALTER TABLE、
DROP TABLE或DROP DATABASE会导致缓存数据失效。所以查询缓存适合有大量相同查询的应用,不适合有大量数据更新的应用。
二级缓存应用场景
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,
提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间
隔 flushInterval ,比如设置为30分钟、60分钟、24小时等,根据需求而定。
七、动态代理
代理模式的定义:被代理者没有能力或者不愿意去完成某件事情,那么就需要找个人代替自己去完成这件事,这个人就是代理者, 所以代理模式包含了3个角色: 被代理角色 代理角色 抽象角色(协议 接口)
底层运用 利用反射机制在运行时创建代理类
public class Hello implements HelloInterface{
@Override
public void sayHello() {
System.out.println("Hello"+"我是类中的");
}
}
public interface HelloInterface {
void sayHello();
}
package Invocation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class Invocation implements InvocationHandler {
private Object object;
public Invocation(Object object){
this.object=object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前面");
Object invoke = method.invoke(object, args);
System.out.println("后面");
return invoke;
}
}
这里有个细节,return!如果return null,那当方法有返回值的时候,是拿不到的。returun method.invoke的对象,这样如果有返回值的时候,可以取到
package test;
import Invocation.Hello;
import Invocation.HelloInterface;
import Invocation.Invocation;
import ybb.YbbArraylist;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import static org.apache.commons.math3.analysis.FunctionUtils.add;
public class test1 {
public static void main(String[] args) {
HelloInterface hello=new Hello();
InvocationHandler invocation = new Invocation(hello);
HelloInterface proxyInstance = (HelloInterface)Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), invocation);
proxyInstance.sayHello();
}
}
jdk提供一个Proxy类可以直接给实现接口类的对象直接生成代理对象
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)生成一个代理对象
参数1 loader:被代理类的类加载器
参数2 interfaces: 被代理类所有实现的接口的Class对象
参数3 InvocationHandler: 执行处理类
前2个参数是为了帮助在jvm内部生成被代理类的代理对象,第3个参数用来监听代理对象调用的方法,帮助我们代理对象调用方法
是不真实存在的,通过实现接口类的对象直接生成代理对象
public Object invoke(Object proxy, Method method, Object[] args);
回调方法: 当代理对象调用了方法,就会来执行该invoke方法, 在该方法中就可以增强被代理类的方法
参数1: 生成的代理对象 这里就是p这个代理对象 (慎用)
参数2: 当前代理对象执行的方法 这里method就是sayHello方法对象
参数3: 当前代理对象执行的方法,传入的实际参数
返回值:当前代理对象执行的方法的返回值
PS:如果在调用Proxy.newProxyInstance方法前设置
System.getProperties().setProperty(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);
加载完会有一个class的字节码文件
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import Invocation.HelloInterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements HelloInterface {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void sayHello() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("Invocation.HelloInterface").getMethod("sayHello");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
八、反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
利用Java反射机制我们可以加载一个运行时才得知名称的class,获悉其构造方法,并生成其对象实体,能对其fields设值并唤起其methods。
运行时动态加载需要加载的对象
Class类:Class是开启反射的源头;
在Object类中定义了以下的方法,此方法将被所有子类继承:
public final Class getClass();
Class本身也是一个类;
Class 对象只能由系统建立对象;
一个类在 JVM 中只会有一个Class实例;
一个Class对象对应的是一个加载到JVM中的一个.class文件;
每个类的实例都会记得自己是由哪个 Class 实例所生成;
通过Class可以完整地得到一个类中的完整结构;
反射需要先创建出来Class类,再通过对应的方法去获取或者操作具体的方法或者属性
Class类
获取有三种方式
- 类名.class
- 对象名.getClass()
- Class.forName(“全类名”)
Constructor 类的构造方法
有无Declared的区别是能否能获取到非公共(protected,private)的的构造方法!
Constructor getConstructor(Class… parameterTypes)
* 根据参数类型获得对应的Constructor对象。
* 只能获得public修饰的构造方法
Constructor getDeclaredConstructor(Class… parameterTypes)
* 根据参数类型获得对应的Constructor对象
可以是public、protected、(默认)、private修饰符的构造方法。
* Constructor[] getConstructors()
获得类中的所有构造方法对象,只能获得public的
* Constructor[] getDeclaredConstructors()
获得类中的所有构造方法对象
可以是public、protected、(默认)、private修饰符的构造方法。
如果不知道可以先通过Class对象.getDeclaredConstructors()获取所有的构造方法,然后再操作
Class类.newInstance() 方法创建该类对象
void setAccessible(true) 设置“暴力反射”—是否取消权限检查,true取消权限检查,false表示不取消
Field类 代表类的成员变量(类的属性)
Class类中与Field相关的方法
* Field getField(String name);
* 根据成员变量名获得对应Field对象,只能获得public修饰
* Field getDeclaredField(String name);
* 根据成员变量名获得对应Field对象,包括public、protected、(默认)、private的
* Field[] getFields();
* 获得所有的成员变量对应的Field对象,只能获得public的
* Field[] getDeclaredFields();
* 获得所有的成员变量对应的Field对象,包括public、protected、(默认)、private的
Method类 代表类的方法
**Method** 类的方法
* Method getMethod(String name,Class...args);
* 根据方法名和参数类型获得对应的构造方法对象,只能获得public的
* Method getDeclaredMethod(String name,Class...args);
* 根据方法名和参数类型获得对应的构造方法对象,包括public、protected、(默认)、private的
* Method[] getMethods();
* 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
* Method[] getDeclaredMethods();
* 获得类中的所有成员方法对象,返回数组,只获得本类的,包括public、protected、(默认)、private的
设置"暴力访问"——是否取消权限检查,true取消权限检查,false表示不取消
**如果不知道可以先通过Class对象.getDeclaredMethods()获取所有的构造方法,然后再操作**
- Object invoke(Object obj, Object… args)
- 调用指定对象obj的该方法
- args:调用方法时传递的参数
- void setAccessible(true)
九、打代码中遇到的问题
在自己做VUE和ELEMENT结合ajax实现前后端登录和数据的增删改查
1.错误Binding.BindingException
Dao层的interface和mapper映射文件,有一个很重要的东西!
如果interface传参只有一个,就没事,如果传参多个,需要在接口方法中指定方法名称!!!
不然会报
这个异常!纪念我卡了一天的bug!
2.VUE 双向绑定问题
基本用在表单中
一定要对应起来,不然调试很麻烦。
3.数据库字段和类属性
数据库字段中会有有时候会有一些下划线(_)这种符号,如果搞不清楚,可以尝试
这样会好理解些
4.数据库中double类型和idea中double类型代表的存储占用空间不一样,要小心
5.html中表单提交页面交互会有BUG,要用ajax技术来实现异步的前后端交互
6.Dao层的interface和mapper映射文件
Dao层的interface和mapper映射文件,有一个很重要的东西!
如果interface传参只有一个,就没事,如果传参多个,需要在接口方法中指定方法名称!!!
不然会报
7.属性和数据库的字段名 匹配
实体类的属性和数据库的字段名一致,可以直接resultType封装,但是如果不一致,用resultMap处理关系的映射,然后封装。如果不一致,是拿不到数据的
8. MAVEN中如果都是好的,要打包不行,看下配置的时候是war还是jar
9. Error querying database. Cause: java.sql.SQLException: Must specify port after ‘:’ in connection string
多半是url配错了
这样就对了
Process finished with exit code -1073741819 (0xC0000005) 和解决maven编译 Process terminated
多半是金山毒霸冲突,删了就好了!!!
十、系统监控功能
问题:监控用户在什么时间请求了什么方法,请求的路径是什么,请求的方法名是什么,这些方法执行耗费了多长时间,把对应的这些数据存到表里面,以上功能完成后需要展示这些数据
思路:
1.根据需求在数据库中建立一个表,id主键自增 int,create_time date ,url varchar,method_name varchar,,waste_time date
2.在类中定义属性和数据库中的字段保持一致
3.然后是三层结构和前端页面,需要两个方法(添加addlog和查找所有findall)
4.重点,过滤器的使用(来回都会经过过滤器,简单了)
domain
public class Log {
private Integer id;
private Date create_time;
private String method_name;
private String method_url;
private Date waste_time;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Date getCreate_time() {
return create_time;
}
public void setCreate_time(Date create_time) {
this.create_time = create_time;
}
public String getMethod_name() {
return method_name;
}
public void setMethod_name(String method_name) {
this.method_name = method_name;
}
public String getMethod_url() {
return method_url;
}
public void setMethod_url(String method_url) {
this.method_url = method_url;
}
public Date getWaste_time() {
return waste_time;
}
public void setWaste_time(Date waste_time) {
this.waste_time = waste_time;
}
public Log(Integer id, Date create_time, String method_name, String method_url, Date waste_time) {
this.id = id;
this.create_time = create_time;
this.method_name = method_name;
this.method_url = method_url;
this.waste_time = waste_time;
}
}
service
public interface LogService {
List<Log> logs();
void addlog(Log log);
}
serviceImpl
package com.ybb.service.Impl;
import com.ybb.dao.LogDao;
import com.ybb.domain.Log;
import com.ybb.service.LogService;
import com.ybb.utils.TransactionUtil;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class LogSericeImpl implements LogService {
@Override
public List<Log> logs() {
InputStream is = null;
SqlSession sqlSession = null;
try {
is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
sqlSession = build.openSession(true);
LogDao mapper = sqlSession.getMapper(LogDao.class);
List<Log> logs = mapper.logs();
return logs;
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void addlog(Log log) {
InputStream is = null;
SqlSession sqlSession = null;
try {
is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
sqlSession = build.openSession(true);
LogDao mapper = sqlSession.getMapper(LogDao.class);
mapper.addlog(log);
TransactionUtil.commit(sqlSession);
} catch (IOException e) {
TransactionUtil.rollback(sqlSession);
throw new RuntimeException(e);
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
TransactionUtil.close(sqlSession);
}
}
}
logServlet
package com.ybb.service.Impl;
import com.ybb.dao.LogDao;
import com.ybb.domain.Log;
import com.ybb.service.LogService;
import com.ybb.utils.TransactionUtil;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class LogSericeImpl implements LogService {
@Override
public List<Log> logs() {
InputStream is = null;
SqlSession sqlSession = null;
try {
is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
sqlSession = build.openSession(true);
LogDao mapper = sqlSession.getMapper(LogDao.class);
List<Log> logs = mapper.logs();
return logs;
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void addlog(Log log) {
InputStream is = null;
SqlSession sqlSession = null;
try {
is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
sqlSession = build.openSession(true);
LogDao mapper = sqlSession.getMapper(LogDao.class);
mapper.addlog(log);
TransactionUtil.commit(sqlSession);
} catch (IOException e) {
TransactionUtil.rollback(sqlSession);
throw new RuntimeException(e);
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
TransactionUtil.close(sqlSession);
}
}
}
过滤器
package com.ybb.web.filter;
import com.ybb.domain.Log;
import com.ybb.service.Impl.LogSericeImpl;
import com.ybb.service.LogService;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
@WebFilter(value = {"/*"})
public class logFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {
try{
//1.将请求和响应对象转换为和HTTP协议相关
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
LogService logService=new LogSericeImpl();
//创建时间
long create_time = System.currentTimeMillis();
//方法
String method = request.getParameter("method");
//路径
String requestURI = request.getRequestURI();
//4.放行
filterChain.doFilter(request,response);
// 耗费的时候
long waste_time = System.currentTimeMillis() - create_time;
Date create = new Date(create_time);
Date waste = new Date(waste_time);
logService.addlog(new Log(null,create,method,requestURI,waste));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void destroy() {
}
}
页面展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>商品管理系统</title>
<link rel="stylesheet" href="element-ui/lib/theme-chalk/index.css">
<script src="js/vue.js"></script>
<script src="element-ui/lib/index.js"></script>
<script src="js/axios-0.18.0.js"></script>
</head>
<body>
<div id="div">
<b style="color: red; font-size: 20px;">日志列表</b>
<el-table :data="tableData">
<el-table-column prop="id" label="日志编号" width="220">
</el-table-column>
<el-table-column prop="create_time" label="请求创建时间" width="220">
</el-table-column>
<el-table-column prop="method_name" label="请求方法名" width="220">
</el-table-column>
<el-table-column prop="method_url" label="请求路径" width="220">
</el-table-column>
<el-table-column prop="waste_time" label="请求耗费时间" width="220">
</el-table-column>
</el-table>
<!--
分页组件
@size-change: 当改变每页条数时触发的函数
@current-change:当改变页码时触发的函数
current-page :默认的页码
:page-sizes:每页条数选择框中显示的值
:page-size : 默认的每页条数
layout: 分页组件的布局
total(总条数), sizes(每页条数), prev(上一页), pager(所有的页码), next(下一页), jumper(跳转页码)
:total: 总条数
-->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pagination.currentPage"
:page-sizes="[3,5,8]"
:page-size="pagination.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total">
</el-pagination>
</div>
</body>
<script>
new Vue({
el:"#div",
data:{
tableData:[],//表格数据
pagination: {
currentPage: 1, //当前页
pageSize: 5, //每页显示条数
total: 0 //总条数
},
},
methods:{
//分页查询功能
selectByPage(){
axios.post("logServlet","method=log¤tPage=" + this.pagination.currentPage + "&pageSize=" + this.pagination.pageSize)
.then(resp => {
//将查询出的数据赋值tableData
this.tableData = resp.data;
//设置分页参数
//当前页
this.pagination.currentPage = resp.data.pageNum;
//总条数
this.pagination.total = resp.data.total;
})
},
//改变每页条数时执行的函数
handleSizeChange(pageSize) {
//修改分页查询的参数
this.pagination.pageSize = pageSize;
//重新执行查询
this.selectByPage();
},
//改变页码时执行的函数
handleCurrentChange(pageNum) {
//修改分页查询的参数
this.pagination.currentPage = pageNum;
//重新执行查询
this.selectByPage();
},
},
mounted(){
//调用分页查询功能
this.selectByPage();
}
});
</script>
</html>