目录
1.准备工作
环境搭建
开发规范
REST(REpresentation State Transfer),表述性状态转换,它是一种软件架构风格
注意事项
统一响应结果
2.部门管理功能
查询部门
删除部门
新增部门
@RequestMapping
3.员工管理功能
分页查询
批量删除员工
编辑新增员工
文件上传
简介
本地存储
修改员工
查询回显
修改员工
参数配置化
配置格式
yml数据格式
4.用户登录功能
登录功能
登录校验
会话技术
会话跟踪方案对比
JWT令牌
JWT-生成
JWT-校验
登录-生成令牌
过滤器Filter
入门程序
FIlter执行流程
Filter拦截路径
过滤器链
登录校验Filter
拦截器Interceptor
快速入门
拦截器-拦截路径
拦截器-执行流程
登录校验Interceptor
异常处理
5.事务管理
Spring事务管理
事务属性-回滚
事务属性-传播行为
场景
6.AOP(面向切面编程)
AOP概述
AOP核心概念
通知类型
@PointCut
通知顺序
切入点表达式
execution表达式
@Annotation注解表达式
连接点
7.配置优先级
8.Bean管理
获取bean
bean作用域
第三方bean
9.SpringBoot原理
自动配置原理
@Conditional注解
1.准备工作
-
环境搭建
-
开发规范
REST(REpresentation State Transfer),表述性状态转换,它是一种软件架构风格
注意事项
- REST是风格,是约定方式,约定不是规定,可以打破
- 描述模块的功能通常使用复数,也就是加s的格式来描述,表示此类资源,而非单个资源。如:users、emps、books
统一响应结果
- 前后端交互统一响应结果Result
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {private Integer code;//响应码,1 代表成功; 0 代表失败private String msg; //响应信息 描述字符串private Object data; //返回的数据//增删改 成功响应public static Result success(){return new Result(1,"success",null);}//查询 成功响应public static Result success(Object data){return new Result(1,"success",data);}//失败响应public static Result error(String msg){return new Result(0,msg,null);}
}
2.部门管理功能
查询部门
/*** 部门管理Controller*/
@Slf4j
@RestController
public class DeptController {// private static Logger log = LoggerFactory.getLogger(DeptController.class);@Autowiredprivate DeptService deptService;// @RequestMapping(value = "/depts",method = RequestMethod.GET) //指定请求方式为GET@GetMapping("/depts")public Result list(){log.info("查询全部部门数据");//调用service查询部门数据List deptList = deptService.list();return Result.success(deptList);}
}@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Overridepublic List list() {return deptMapper.list();}
}@Mapper
public interface DeptMapper {/*** 查询全部部门* @return*/@Select("select * from dept")List list();
}
删除部门
/*** 删除部门数据*/@DeleteMapping("/depts/{id}")public Result delete(@PathVariable Integer id){log.info("根据id删除部门:{}",id);DeptService.delete(id);return Result.success();}@Overridepublic void delete(Integer id) {deptMapper.deleteById(id);}/*** 根据id删除部门* @param id*/@Delete("delete from dept where id = #{id}")void deleteById(Integer id);
新增部门
/*** 新增部门数据*/@PostMapping("/depts")public Result add(@RequestBody Dept dept){log.info("新增部门:{}" , dept);deptService.add(dept);return Result.success();}@Overridepublic void add(Dept dept) {dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.insert(dept);}@Insert("insert into mybatis.dept(name, create_time, update_time ) values (#{name},#{createTime},#{updateTime})")void insert(Dept dept);
@RequestMapping
3.员工管理功能
分页查询
@Slf4j
@RestController
public class EmpController {@Autowiredprivate EmpService empService;@GetMapping("/emps")public Result page(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "10") Integer pageSize){log.info("分页查询,参数:{},{}",page,pageSize);//调用service分页查询PageBean pageBean = empService.page(page,pageSize);return Result.success(pageBean);}}@Service
public class EmpServiceImpl implements EmpService {@Autowiredprivate EmpMapper empMapper;@Overridepublic PageBean page(Integer page, Integer pageSize) {//1.获取总记录数Long count = empMapper.count();//2.获取分页查询结果列表Integer start = (page - 1) * pageSize;List<Emp> empList = empMapper.page(start, pageSize);//3.封装PageBean对象PageBean pageBean = new PageBean(count, empList);return pageBean;}
}@Mapper
public interface EmpMapper {/*** 查询总记录数* @return*/@Select("select count(*) from emp")public Long count();/*** 分页查询,获取列表数据* @param start* @param pageSize* @return*/@Select("select * from emp limit #{start},#{pageSize}")public List<Emp> page(Integer start,Integer pageSize);
}
批量删除员工
新增员工
文件上传
简介
- 文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程
前端页面三要素
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>上传文件</title>
</head>
<body><form action="/upload" method="post" enctype="multipart/form-data">姓名: <input type="text" name="username"><br>年龄: <input type="text" name="age"><br>头像: <input type="file" name="image"><br><input type="submit" value="提交"></form></body>
</html>
服务端接口
@PostMapping("/upload")public Result upload(String username, Integer age, MultipartFile image){log.info("文件上传:{},{},{}" ,username,age,image);return Result.success();}
本地存储
- 在服务端,接收到上传来的文件之后,将文件存储在本地服务器磁盘中
@PostMapping("/upload")public Result upload(String username, Integer age, MultipartFile image) throws IOException {log.info("文件上传:{},{},{}" ,username,age,image);//获取原始文件名String originalFilename = image.getOriginalFilename();//构造唯一的文件名 - uuid(通用唯一识别码)int index = originalFilename.lastIndexOf(".");String extname = originalFilename.substring(index);String newFileName = UUID.randomUUID().toString()+ extname;log.info("新的文件名: {}" ,newFileName);//将文件存储在服务器的磁盘目录中E:\imagesimage.transferTo(new File("E:\\images\\" + newFileName));return Result.success();}
在Springboot中,文件上传,默认单个文件允许最大大小为1M。如果需要上传大文件,可以进行如下配置:
#配置单个文件上传大小限制
spring.servlet.multipart.max-file-size=10MB
#配置单个请求最大大小的限制(一次请求中是可以上传多个文件)
spring.servlet.multipart.max-request-size=100MB
修改员工
-
查询回显
-
修改员工
参数配置化
配置格式
yml数据格式
#定义对象/Map集合
user:name:Tomage:20address:beijing#定义数组/List/Set
hobby:- java- C- game- sport
4.用户登录功能
-
登录功能
@RestController
@Slf4j
public class loginController {private EmpService empService;@PostMapping("/login")public Result login(@RequestBody Emp emp){log.info("员工登录:{}",emp);Emp e = empService.login(emp);return e != null ?Result.success():Result.error("用户名或密码错误");}
}@Overridepublic Emp login(Emp emp) {return empMapper.getByUsernameAndPassword(emp);}/*** 根据用户名和密码查询员工* @param emp* @return*/@Select("select * from emp where username = #{usernae} and password = #{password}")Emp getByUsernameAndPassword(Emp emp);
}
登录校验
会话技术
- 会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。
- 会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据
- 会话跟踪方案:
- 客户端会话跟踪技术:Cookie
- 服务端会话跟踪技术:Session
- 令牌技术(企业主流)
会话跟踪方案对比
JWT令牌
- 全称:JSON Web Token
- 定义了一张简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息
- 组成:
- 第一部分:Header(头),记录令牌类型、签名算法
- 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息
- 第三部分:Signature(签名),防止Token被篡改、确保安全性
- 场景:登录认证
- ①登录成功后,生成令牌
- ②后续每个请求,都有携带JWT令牌,系统在每次请求处理之前,先校验令牌,通过后,再处理
JWT-生成
JWT-校验
登录-生成令牌
@Autowiredprivate EmpService empService;@PostMapping("/login")public Result login(@RequestBody Emp emp){Emp e = empService.login(emp);//登录成功,生成令牌,下发令牌if(e != null){Map<String, Object> claims = new HashMap<>();claims.put("id",e.getId());claims.put("name",e.getName());claims.put("username",e.getUsername());//生成Jwt令牌String jwt = JwtUtils.generateJwt(claims);return Result.success(jwt);}return Result.error("错误");}
过滤器Filter
- 概念:是JavaWeb三大组件之一
- 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能
入门程序
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {@Override //初始化方法,只调用一次public void init(FilterConfig filterConfig) throws ServletException {System.out.println("init 初始化方法执行了");}@Override //拦截到请求之后调用,调用多次public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("拦截到了请求");//放行filterChain.doFilter(servletRequest, servletResponse);}@Override //销毁方法,只调用一次public void destroy() {System.out.println("destroy 销毁方法执行了");}
}
FIlter执行流程
Filter拦截路径
过滤器链
- 介绍:一个Web应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链
- 顺序:注解配置的Filter,优先级是按照过滤器类名的自然排序
登录校验Filter
@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) servletRequest;HttpServletResponse resp = (HttpServletResponse) servletResponse;//1.获取请求urlString url = req.getRequestURI().toString();log.info("请求的url:{}",url);//2.判断请求url中是否包含login,如果包含,说明是登录操作,放行if(url.contains("login")){log.info("登录操作,放行...");filterChain.doFilter(servletRequest, servletResponse);return;}//3.获取请求头中的令牌(token)String jwt = req.getHeader("token");//4.判断令牌是否存在,如果不存在,返回错误结果if(!StringUtils.hasLength(jwt)){log.info("请求头token为空,返回未登录的信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json ---------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return;}//5.解析token,如果解析失败,返回错误结果try {JwtUtils.parseJWT(jwt);} catch (Exception e) {e.printStackTrace();log.info("解析令牌失败,返回未登录的信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json ---------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return;}//6.放行log.info("令牌合法,放行");filterChain.doFilter(servletRequest, servletResponse);}
}
拦截器Interceptor
- 概念:是一种动态拦截方法调用的机制,类似于过滤器。Spring框架提供的,用来动态拦截控制器方法的执行
快速入门
拦截器-拦截路径
拦截器-执行流程
- 接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口
- 拦截范围不同:过滤器会拦截所有的资源,而拦截器只会拦截Spring环境的资源
登录校验Interceptor
@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {@Override //目标资源方法运行前运行,返回true:放行,返回false,不放行public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {//1.获取请求urlString url = req.getRequestURI().toString();log.info("请求的url:{}",url);//2.判断请求url中是否包含login,如果包含,说明是登录操作,放行if(url.contains("login")){log.info("登录操作,放行...");return true;}//3.获取请求头中的令牌(token)String jwt = req.getHeader("token");//4.判断令牌是否存在,如果不存在,返回错误结果if(!StringUtils.hasLength(jwt)){log.info("请求头token为空,返回未登录的信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json ---------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);return false;}//5.解析token,如果解析失败,返回错误结果try {JwtUtils.parseJWT(jwt);} catch (Exception e) {e.printStackTrace();log.info("解析令牌失败,返回未登录的信息");Result error = Result.error("NOT_LOGIN");//手动转换 对象--json ---------> 阿里巴巴fastJSONString notLogin = JSONObject.toJSONString(error);return false;}//6.放行log.info("令牌合法,放行");return true;}@Override //目标资源方法运行后运行public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle...");}@Override //视图渲染完毕后运行,最后运行public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion...");}
}
异常处理
/*** 全局异常处理器*/
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class) //捕获所有异常public Result ex(Exception ex){ex.printStackTrace();return Result.error("对不起,操作失败,请联系管理员");}
}
5.事务管理
Spring事务管理
- 注解:@Transactional
- 位置:业务层的方法上、类上、接口上
- 作用:将当前方法交给spring进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务
@Transactional //spring事务管理@Overridepublic void delete(Integer id) {deptMapper.deleteById(id);int i = 1/0;empMapper.deleteByDeptId(id);}
事务属性-回滚
rollbackFor:默认情况下,只有出现运行时异常RuntimeException才回滚异常。rollbackFor属性用于控制出现何种异常类型,回滚事务。
@Transactional(rollbackFor = Exception.class) //spring事务管理@Overridepublic void delete(Integer id) {deptMapper.deleteById(id);int i = 1/0;empMapper.deleteByDeptId(id);}
事务属性-传播行为
propagation:指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制
场景
- REQUIRED:大部分情况下都是用该传播行为
- REQUIRED_NEW:当我们不希望事务之间相互影响时,可以使用。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功
6.AOP(面向切面编程)
AOP概述
- AOP:Aspect Oriented Programing,其实就是面向特定方法编程
- 场景:
- 实现:
- 动态代理是面向切面编程最主流的实现。而SpringAOP是Spring框架的高级技术,在管理bean对象的过程中,主要通过底层的动态代理机制,对特定的方法进行编程
AOP核心概念
- 连接点:JoinPoint,可以被AOP控制的方法
- 通知:Advice,指哪些重复的逻辑,也就是共性功能
- 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
- 切面:Aspect,描述通知与切入点的对应关系(通知+切入点)
通知类型
@PointCut
- 该注解的作用是将公共的切入点表达式抽取出来,需要用到时引用该切点表达式即可
通知顺序
切入点表达式
- 描述切入点方法的一种表达式
- 作用:主要用来决定项目中的哪些方法需要加入通知
- 常见形式:
- 1.execution:根据方法的签名来匹配
- 2.@annotation:根据注解匹配
execution表达式
@Annotation注解表达式
连接点
- 在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等
- 对于@Around通知,获取连接点信息只能使用ProceedingJoinPoint
- 对于其他四种通知,获取连接点只能使用JoinPoint,它是ProceedingJoinPoint的父类型
7.配置优先级
8.Bean管理
获取bean
- 默认情况下,Spring项目启动时,会把bean都创建好放在IOC容器中,如果想要主动获取这些bean,可以通过如下方式:
@Autowiredprivate ApplicationContext applicationContext; //IOC容器对象//获取bean对象@Testpublic void testGetBean(){//根据bean的名称获取DeptController bean1 = (DeptController) applicationContext.getBean("deptController");System.out.println(bean1);//根据bean的类型获取DeptController bean2 = applicationContext.getBean(DeptController.class);System.out.println(bean2);//根据bean的名称 及 类型获取DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);System.out.println(bean3);
}
bean作用域
第三方bean
@Bean
- 如果要管理的bean对象来自第三方(不是自定义的),是无法用@Component及衍生注解声明bean的,就需要用到@Bean注解
- 若要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过@Configuration注解声明一个配置类
@Configuration //配置类
public class CommonConfig {//声明第三方bean@Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean//通过@Bean注解的name/value属性指定bean名称, 如果未指定, 默认是方法名public SAXReader reader(DeptService deptService){System.out.println(deptService);return new SAXReader();}}
9.SpringBoot原理
- 起步依赖:依赖传递
- 自动配置
Springboot的自动配置就是当spring容器启动后,一些配置类、bean对象IU自动存入到了IOC容器,不需要我们手动去声明,简化了开发
自动配置原理
@Conditional注解
- 作用:按照一定的条件进行判断,在满足条件后才会注册对应的bean对象到Spring IOC容器中
- 位置:方法、类
- @Conditional本身是一个父注解,派生出大量的子注解
- @ConditionalOnClass:判断环境中是否有对应字节码文件,才注册bean到IOC容器