项目简介:
笔记管理系统,用户可以管理笔记信息,可以查看其他用户分享的笔记。
主要功能如下:
-用户模块:登录、注册、修改密码、退出
-笔记本模块:创建、删除、更新、查看
-笔记模块:创建、删除、更新、查看、转移
-分享和收藏模块:分享、收藏、查看、搜索分享
-回收站模块:查看、彻底删除、恢复
-活动模块:查看活动、参加活动等
使用的主要技术:
-jQuery:简化前端javascript和ajax编程
-Ajax:页面局部处理;提升用户体验和性能
-SpringMVC:负责接收请求,调用业务组件处理,将结果生成JSON响应输出
-SpringIOC:负责管理Controller,Service,Dao维护这些组件对象之间的关系
-MyBatis:负责实现数据库操作,实现Dao
-SpringAOP:负责事务和异常日志功能切入(不用修改原有组件代码,就可以追加功能)
服务器端返回JSON字符串:
1. 配置DispatcherServlet
2. 配置handlerMapping
3. 根据请求编写Controller
4. 扫描(将Controller配置到Spring容器)
5. 调用jackson包将返回的对象、List集合、Map集合转成JSON字符串输出
项目分层流程:
表现层 --> 控制层 --> 业务层 --> 持久层/数据访问层
HTML(ajax)-->Controller-->Service-->Dao
JSP响应流程:
请求-->DispatcherServlet
--> HandlerMapping
--> Controller
--> 返回ModelAndView/String
--> ViewResolver
--> JSP -->响应
JSON响应流程:
请求-->DispatcherServlet
--> HandlerMapping
--> Controller
--> 返回数据对象(int,User,List<User>,Map)
--> 引入jackson包,在Controller方法前添加@ResponseBody标记
--> JSON响应
MyBatis访问数据库流程:
Spring+MyBatis访问数据库流程:
Ajax工作流程:
HTML页面中几种click事件处理:
1. 元素.click(fun);//绑定单击fun
2. 元素.click();//触发单击
3. 父元素.on("click","子元素",fun);//为将来的元素(动态加载的元素)绑定事件
4. $(fun) = onload(); //等价关系
Spring事务管理:
1. 事务作用:保障一组数据库SQL操作的完整性。
2. 项目中事务:默认情况下,每个Dao方法都是一个独立事务,如果Service方法使用两个Dao方法处理,无法保障Service方法的完整性
//默认事务 public void someServiceMethod(){ dao.save();//开始事务,提交/回滚 dao.update();//开始事务,提交/回滚 } //采用事务保证service处理完整性 public void someServiceMethod(){ try{ //开启事务 Service.shareNote()方法 //提交事务 }catch(){ //异常回滚事务 } }
如果按上面结构改动,需要对每个Service组件方法修改,工作量非常大。可以采用Spring来进行事务控制,工作量非常小,而且非常灵活。
3. Spring事务处理:
Spring提供了事务管理的封装,不同技术提供的封装组件不同,例如JDBC和MyBatis采用DataSourceTransactionManager组件封装了事务commit和捕获异常后rollback。Spring底层借助了AOP机制将DataSourceTransactionManager作用到业务方法上去。(基于配置方式):
@Transactional public void f1(){...} //执行效果等价于 try{ 开启事务 调用f1(); 提交事务 }catch(){ 回滚事务 }
4. 重点掌握使用方法(XML配置/注解配置):
a. <bean>定义DataSourceTransactionManager事务管理
b. 开启@Transactional注解<tx:annotation-driven/>
c. 在业务组件类前或方法前使用@Transactional标记
5. @Transactional标记属性(控制事务属性):
a. 可读写特性readOnly:
默认可读可写;如果遇到只有select操作的方法可以采用只读事务。
使用格式: @Transactional(readOnly=true)
b. 回滚特性rollbackFor:
默认RuntimeException回滚,其他异常不回滚。
@Transactional
public void f1(){
//db操作
//发生了IOException
}
默认使用:db操作无法撤销,如果需要撤销需要使用@Transactional(rollbackFor=IOException.class)。
c. 传播特性propagation:
一般采用默认传播类型,类型为REQUIRED。
[java] view plain copy
- @Transactional
- public void f1(){
- //业务代码A
- f2();
- //业务代码B
- }
- @Transactional
- public void f2(){
- //业务代码C; //默认C出错会影响f1的A
- }
d.隔离特性isolation:
一般采用默认隔离级别,级别为READ_COMMITED。产生原因是因为:事务的并发(两段数据库操作代码并发,容易产生脏读、幻读、更新丢失等问题)。解决方案就是采用隔离级别设置,将两个事务操作代码隔离开。
@Transactional标记事务隔离级别有以下几种:
- READ_UNCOMMITTED 读未提交(级别最低);
- READ_COMMITTED 读已提交;
- REPEATABLE_READ 可重复读;
- SERIALIZABLE 序列化操作(级别最高)
- DEFAULT 根据数据库自动选择READ_COMMITTED或REPEATABLE_READ
级别越高安全性越好,但是并发处理能力越低。一般使用时,选择默认DEFAULT,之后如果有安全性需求,会由程序员编写代码逻辑解决(悲观锁和乐观锁)。
e. Spring中常用的事务类型:
REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与REQUIRED类似的操作。
拥有多个可以回滚的保存点,内部回滚不会对外部事务产生影响。只对DataSourceTransactionManager有效。
Spring AOP知识点总结:
1. AOP与OOP对比:
Aspect OrientedProgramming (AOP):面向切面编程(重点:共同业务处理;优点:可以在不用修改原有组件逻辑代码情况下,通过配置追加新的处理功能);
Object OrientedProgramming (OOP):面向对象编程(重点:对象分析和设计)。
2. 项目涉及AOP应用:
a.追加事务控制;
b.追加异常日志记录。
3. AOP入门示例(掌握用注解实现):
- 将共同处理封装成一个组件;
- 追加AOP配置,将共同组件作用到目标方法上。
4. AOP相关概念:
OOP:类,对象,继承,多态;
AOP:切面,切入点,通知,动态代理。
a. 切面(Aspect):指的是封装了共同处理的组件,并且能够切入到其他目标组件方法上(带有@Aspect标记的Bean组件)。
b. 切入点(Pointcut):用于指定目标组件及方法。Spring提供了,以下几种切入点表达式:
>方法限定表达式:可以指定某个组件中部分方法追加共同功能。
execution(修饰符? 返回类型方法名(参数) 抛出异常?)
//匹配所有add打头的方法
execution(*add*(..))
//匹配UserService组件中所有方法
execution(*com.service.UserService.*(..))
//匹配com.service下所有类所有方法
execution(*com.service.*.*(..))
//匹配com.service包及子包下所有类所有方法
execution(*com.service..*.*(..))
>类型限定表达式:可以指定某个组件中所有方法追加共同功能。
within(类型)
//匹配UserService组件所有方法
within(com.service.UserService)
//匹配com.service包下所有类所有方法
within(com.service.*)
//匹配com.service包及子包下所有类所有方法
within(com.service..*)
>bean名称限定表达式:可以指定某个组件中所有方法追加共同功能。
bean(id名)
//匹配id=userService的组件所有方法
bean(userService)
//匹配所有id名以Service结尾的组件所有方法
bean(*Service)
c. 通知(Advice):用于指定切入的时机。指定切面功能在什么时机插入到目标组件方法中。Spring提供以下5种通知类型 (环绕通知=前置+后置):
try{ -使用前置通知<aop:before> //执行目标组件方法(Service方法) -使用后置通知<aop:after-returning> }catch(){ -使用异常通知<aop:after-throwing> }finally{ -使用最终通知<aop:after> }
4. 通俗理解:
切面:追加啥功能? 打桩信息;
切入点:切谁? 所有Controller;
通知:啥时候切?前置通知。
5. 什么是Spring AOP?实现原理?
面向切面编程,目的是将共同业务从传统业务中抽离出来,单独封装,然后以配置方式进行关联。
优点:实现了共同业务和传统业务的解耦,使程序员将精力放在传统的业务编写上。
Spring AOP实现原理采用的是动态代理技术。动态代理技术:可以动态创建类的技术。
当Spring采用AOP切入后,Spring容器给使用者返回的是采用动态代理技术生成的一个新类型,新类型重写了原有目标组件的方法,在重写方法中调用切入的功能和原有目标组件功能。
ublic class$Proxy28 implements UserService{ publicvoid checkLogin(){ //调用事务处理 //调用UserServiceImpl.checkLogin处理 }
6. Spring底层有两种动态技术
a.采用JDK的java.reflect.Proxy API(接口):可以根据指定接口生成代理类。
public class代理类 implements 目标接口{
//重写接口方法
}
b.采用CGLIB包(无接口):可以根据指定的类生成代理类。
public class代理类 extends 目标类{
//重写父类方法
}
MyBatis框架的动态技术:
作用:可以在定义SQL的XML文件中拼凑一个SQL语句。MyBatis提供了一组标签,如下:
<if test="条件">...</if> <choose> <when test="条件1">...</when> <when test="条件2">...</when> <otherwise>...</otherwise> </choose> <foreach collection="array" item="id" separator="," open="(" close=")"> #{id} </foreach>
MyBatis关联映射:
作用:可以加载多个相关表的记录,封装成实体对象。
1. 单个对象关联:
public class Book{ //Book的属性 //追加关联属性 private User user; }
2. 多个对象关联(集合):
public class User{ //User的属性 //追加关联属性 private List<Book> books; }
主键字段处理:
如果利用数据库自动递增或序列方式生成主键值,在执行完insert语句后,如何立刻返回数据库生成的主键值?
<!-- MySQL:数据库自动生成的主键获取后放入到参数Emp对象的id属性中 --> <insert id="save" useGeneratedKeys="true" keyProperty="id" parameterType="com.tedu.cloudnote.entity.Emp"> insert into t_emp (name,age) values (#{name},#{age}) </insert> <!--Oracle:先执行序列查询主键值,然后将值放入参数Emp对象的id属性中,最后执行insert语句 --> <insert id="save" parameterType="com.tedu.cloudnote.entity.Emp"> <selectKey order="BEFORE" resultType="int" keyProperty="id"> select emp_seq.nextval from dual </selectKey> insert into t_emp (id,name,age) values (#{id},#{name},#{age}) </insert>
系统权限检测:
a. 主要实现思路:
1. 用户登录成功,生成一个令牌号
2. 将令牌号返回给客户端存入cookie,同时更新用户表的令牌字段
3. 其他操作请求,必须携带用户ID和令牌号, 进入权限检查拦截器进行检查
4. 在拦截器中检测token和用户ID是否匹配;token是否过期等检测
5. 如果通过检测就允许执行后续操作; 未通过检测就阻止后续操作
b. 系统其他操作、笔记本、笔记等:
发送Ajax请求,需要获取token:
-先检查token有无(在html页面利用js 获取Cookie信息检测)
-检查token是否盗用:(请求提交userId和token,检测与数据库cnuser表存储的cnuser_id和token 是否匹配,使用拦截器封装该功能)
-检查token是否过期:(在生成token时可以嵌入时间信息就可以检查了,使用拦截器封装该功能)
c. 登录改造:
1. 检查用户名和密码是否正确(已完成)
2. 创建一个Token,给用户颁发(Cookie)
3. 将token存入用户信息表(更新)