javaweb笔记(中,项目案例)

---黑马)

案例

 开发规范Restful

 

 开发流程

 案例-部门管理-查询

 

 controller层

package ikun.study.controller;

import ikun.study.pojo.Dept;
import ikun.study.pojo.Result;
import ikun.study.service.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * 部门管理Controller
 */
@Slf4j // == private static Logger log = LoggerFactory.getLogger(DeptController.class);
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    /**<a href="http://demo.org:8080/depts">查询全部部门数据</a>
     * 只允许get请求 其他请求方法报405*/
//    @RequestMapping(value = "/depts",method = RequestMethod.GET)
    @GetMapping("/depts")
    public Result list() {
        log.info("查询全部部门数据");
        List<Dept> deptList = deptService.list();

        return Result.success(deptList);
    }
}

service层接口

package ikun.study.service;

import ikun.study.pojo.Dept;

import java.util.List;

/**
 * 部门管理
 */
public interface DeptService {
    /**
     * 查询全部数据
     * */
    List<Dept> list();


}

 service层实现类

package ikun.study.service.impl;

import ikun.study.mapper.DeptMapper;
import ikun.study.pojo.Dept;
import ikun.study.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class DeptServiceImpl implements DeptService {
    @Autowired
    private DeptMapper deptMapper;

    @Override
    public List<Dept> list() {
        return deptMapper.list();
    }
}

mapper层

package ikun.study.mapper;

import ikun.study.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * 部门管理
 */
@Mapper
public interface DeptMapper {
    /**
     * 查询全部部门数据
     * */
    @Select("select * from dept")
    List<Dept> list();
}

删除部门-思路

  controller层

    /**
     * 删除部门数据
     */
    @DeleteMapping("/depts/{id}")
    public Result delete(@PathVariable Integer id) {
        log.info("根据id删除部门:{}",id);
        //调用service删除部门
        deptService.delete(id);
        return Result.success();
    }

service层接口

    /**
     * 删除部门
     * */
    void delete(Integer id);
}

service层实现类

    @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);
    }

mapper层

    /**删除部门*/
    @Delete("delete from dept where id=#{id}")
    void deleteById(Integer id);

新增部门-思路

  controller层

    /**新增部门*/
    @PostMapping("/depts")
    public Result add(@RequestBody Dept dept) {
        log.info("新增部门:{}",dept);
        // 调用service新增部门
        deptService.add(dept);

        return Result.success();
    }

service层接口

    /**
     * 新增部门
     * */
    void add(Dept dept);

service层实现类

    @Override
    public void add(Dept dept) {
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.insert(dept);
    }

mapper层

    /**新增部门*/
    @Insert("insert into dept(name, create_time, update_time) values (#{name},#{createTime},#{updateTime})")
    void insert(Dept dept);

优化

 

 

 案例-员工管理-分页查询

 

//仰晨study 创建时间2023/4/22 2:57 星期六
package ikun.study.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**分页查询结果封装类*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean {
    private Long total;//总记录数
    private List rows;//数据列表
}

 分页插件Pagehelper

 

 控制层

package ikun.study.controller;

import ikun.study.pojo.PageBean;
import ikun.study.pojo.Result;
import ikun.study.service.EmpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * 员工管理Controller
 */
@Slf4j
@RestController
@RequestMapping("/emps")
public class EmpController {
    @Autowired
    private EmpService empService;

    /**<a href="http://demo.org:8080/emps">分页查询</a>*/
    @GetMapping
    public Result parse(@RequestParam(defaultValue = "1") Integer page,     //前端没给就设置默认值1 @RequestParam(defaultValue = "1")
                        @RequestParam(defaultValue = "10") Integer pageSize) {
        log.info("分页查询,参数:{} {}",page,pageSize);
        //调用service分页查询
        PageBean pageBean = empService.page(page,pageSize);
        return Result.success(pageBean);
    }

}

 服务层

package ikun.study.service;

import ikun.study.pojo.PageBean;

/**
 * 员工管理
 */
public interface EmpService {
    /**分页查询*/
    PageBean page(Integer page, Integer pageSize);
}

package ikun.study.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import ikun.study.mapper.EmpMapper;
import ikun.study.pojo.Emp;
import ikun.study.pojo.PageBean;
import ikun.study.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class EmpServiceImpl implements EmpService {
    @Autowired
    private EmpMapper empMapper;

    @Override
    public PageBean page(Integer page, Integer pageSize) {
        // 1、获取总记录数
        // 2、获取分页查询结果列表
        // 3、封装在pageBean对象
        // return new PageBean(empMapper.count(), empMapper.page((page-1)*pageSize,pageSize));

        // 1、设置分页参数
        PageHelper.startPage(page, pageSize);
        // 2、执行查询
        List<Emp> list = empMapper.list();
        Page<Emp> p = (Page<Emp>) list;
        // 3、封装pageBean对象
        return new PageBean(p.getTotal(), p.getResult());
    }
}

数据持久化层

package ikun.study.mapper;

import ikun.study.pojo.Emp;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * 员工管理
 */
@Mapper
public interface EmpMapper {
//    /**
//     * 查询总记录数
//     */
//    @Select("select count(*) from emp")
//    public Long count();
//
//    /**
//     * 分页查询,获取列表数据
//     */
//    @Select("select * from emp limit #{start},#{pageSize}")
//    public List<Emp> page(Integer start, Integer pageSize);

    /**员工信息查询 (统计和分页靠插件)*/
    @Select("select * from emp")
    public List<Emp> list();

}

条件分页查询 

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ikun.study.mapper.EmpMapper">

    <select id="list" resultType="ikun.study.pojo.Emp">
        select * from emp
        <where>
            <if test="name!=null and name!=''">
                name like concat('%',#{name},'%')
            </if>

            <if test="gender!=null">
                and gender = #{gender}
            </if>

            <if test="begin!=null and end!=null">
                and entrydate between #{begin} and #{end}
            </if>

        </where>
        order by update_time desc
    </select>
</mapper>

 案例-员工管理-删除员工

 

案例-员工管理-新增员工

 

    @PostMapping
    public Result save(@RequestBody Emp emp) {
        log.info("新增员工:{}",emp);
        empService.save(emp);
        return Result.success();
    }
    /**新增员工*/
    void save(Emp emp);
   /**新增员工*/
    @Override
    public void save(Emp emp) {
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        empMapper.insert(emp);
    }
    /**新增员工*/
    @Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +
            "VALUES (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
    void insert(Emp emp);

文件上传

 

 

 

 

 

 @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:\Users\Dell\Desktop\
        image.transferTo(new File("E:\\Users\\Dell\\Desktop\\"+newFileName));
        return Result.success();
    }

 设置允许上传的文件大小

# 配置单个文件大小的限制 默认是1m
spring.servlet.multipart.max-file-size=10MB
# 配置多个文件(也叫单次请求)大小的限制 默认是10m
spring.servlet.multipart.max-request-size=100MB

阿里云(不知道怎么写了)

 

 案例-员工管理-修改员工信息

 

<!--更新员工信息-->
    <update id="update">

        UPDATE emp
        <set>
            <if test="username!=null and username!=''">username=#{username},</if>
            <if test="password!=null and password!=''">password=#{password},</if>
            <if test="name!=null and name!=''">name=#{name},</if>
            <if test="gender!=null">gender=#{gender},</if>
            <if test="image!=null and image!=''">image=#{image},</if>
            <if test="job!=null">job=#{job},</if>
            <if test="entrydate!=null">entrydate=#{entrydate},</if>
            <if test="deptId!=null">dept_id=#{deptId},</if>
            <if test="updateTime!=null">update_time=#{updateTime},</if>
        </set>
        WHERE id=#{id};
    </update>

 

案例-配置文件-参数配置化

 

配置文件yml-yaml

 

server:
  port: 9000

# 定义对象/Map集合
user:
  name: ikun
  age: 110
  address: 蔡徐村

# 定义数组/List/set
hobby:
  - java
  - python
  - C

application.properties转 application.yml

#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/tlias
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=123456

#配置mybatis的日志, 指定输出到控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

#开启mybatis的驼峰命名自动映射开关 a_column ------> aCloumn
mybatis.configuration.map-underscore-to-camel-case=true

# 配置单个文件大小的限制 默认是1m
spring.servlet.multipart.max-file-size=10MB
# 配置多个文件(也叫单次请求)大小的限制 默认是10m
spring.servlet.multipart.max-request-size=100MB


# 阿里云OSS配置
aliyun.oss.endpoint=https://oss-cn-guangzhou.aliyuncs.com
aliyun.oss.accessKeyId=LTAI5tA7U94UYbRojy1Q9AQF
aliyun.oss.accessKeySecret=ZFNZN48828Lt0VIBEb2PvhsT2MRXia
aliyun.oss.bucketName=ikunikun
spring:
  # 数据库的连接信息
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/tlias
    username: root
    password: 123456
  # 文件上传配置
  servlet:
    multipart:
      max-file-size: 10MB       # 配置单个文件大小的限制 默认是1m
      max-request-size: 100MB   # 配置多个文件(也叫单次请求)大小的限制 默认是10m


# Mybatis配置
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #配置mybatis的日志, 指定输出到控制台
    map-underscore-to-camel-case: true                    #开启mybatis的驼峰命名自动映射开关

# 阿里云配置
aliyun:
  oss:
    endpoint: https://oss-cn-guangzhou.aliyuncs.com
    accessKeyId: LTAI5tA7U94UYbRojy1Q9AQF
    accessKeySecret: ZFNZN48828Lt0VIBEb2PvhsT2MRXia
    bucketName: ikunikun

 

登录接口 

    @PostMapping("/login")
    public Result login(@RequestBody Emp emp) {
        log.info("用户登录:{}",emp);
//        emp = empService.login(emp);
//        if (emp==null) return Result.error("账号或密码错误");
//        return Result.success(emp);
        return empService.login(emp)==null?Result.error("账号或密码错误"):Result.success();
    }
    /**用户登录*/
    Emp login(Emp emp);
    @Override
    public Emp login(Emp emp) {
        return empMapper.getByUsernameAndPassword(emp);
    }
    @Select("select * from emp where username = #{username} and password = #{password}")
    Emp getByUsernameAndPassword(Emp emp);

登录效验

 会话技术

 

 

 

 

 

JWT令牌

 

    /**生成JWT*/
    @Test
    public void testGenJwt() {
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", 666);
        claims.put("name", "Ikun");


        String jwt = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256, "ikun")  //签名算法+密钥
                .setClaims(claims)  //自定义内容(载荷)
                .setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))//设置有效时间时间为1小数
                .compact();//变成字符串
        System.out.println("jwt = " + jwt);
    }

    /**
     * 解析JWT令牌
     */
    @Test
    public void testParseJwt() {
        Claims claims = Jwts.parser()
                .setSigningKey("ikun")
                .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiSWt1biIsImlkIjo3NzcsImV4cCI6MTY4MjI2MTM1MH0=.vKu_uXjnOAt-_67nuCU22A2vt8P1KLo-DXM7cOHpJV4")
                .getBody();
        System.out.println(claims);
    }

 

package ikun.study.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;

public class JwtUtils {

    private static String signKey = "ikun";
    private static Long expire = 43200000L;   //过期时间为12个小时

    /**
     * 生成JWT令牌
     * @param claims JWT第二部分负载 payload 中存储的内容
     * @return
     */
    public static String generateJwt(Map<String, Object> claims){
        String jwt = Jwts.builder()
                .addClaims(claims)
                .signWith(SignatureAlgorithm.HS256, signKey)
                .setExpiration(new Date(System.currentTimeMillis() + expire))
                .compact();
        return jwt;
    }

    /**
     * 解析JWT令牌
     * @param jwt JWT令牌
     * @return JWT第二部分负载 payload 中存储的内容
     */
    public static Claims parseJWT(String jwt){
        Claims claims = Jwts.parser()
                .setSigningKey(signKey)
                .parseClaimsJws(jwt)
                .getBody();
        return claims;
    }
}
//仰晨study 创建时间2023/4/23 18:39 星期日
package ikun.study.controller;

import ikun.study.pojo.Emp;
import ikun.study.pojo.Result;
import ikun.study.service.EmpService;
import ikun.study.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@RestController
public class LoginController {
    @Autowired
    private EmpService empService;

    @PostMapping("/login")
    public Result login(@RequestBody Emp emp) {
        log.info("用户登录:{}",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());

            String jwt = JwtUtils.generateJwt(claims);  //jwt包涵当前登录员工信息
            return Result.success(jwt);

        }
        //登录失败,返回错误信息
        return Result.error("账号或密码错误");
    }
}

过滤器(Filter)

 快速入门

//仰晨study 创建时间2023/4/23 23:58 星期日
package ikun.study.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;//过滤器
import java.io.IOException;
@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

 

//仰晨study 创建时间2023/4/24 1:00 星期一
package ikun.study.filter;

import com.alibaba.fastjson.JSONObject;
import ikun.study.pojo.Result;
import ikun.study.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@WebFilter("/*")
public class LoginCheckFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        //1.获取请求URL
        String url = req.getRequestURI();
        log.info("请求的URL为:{}",url);

        //2.判断请求头是否包含登录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   -=》阿里巴巴fastJSON
            String 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   -=》阿里巴巴fastJSON
            String notLogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return;
        }

        //6.放行
        log.info("令牌合法,放行");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

 拦截器(interceptor)

 

 ctrl+O==选择实现方法

//仰晨study 创建时间2023/4/24 1:45 星期一
package ikun.study.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override   //目标资源方法运行前运行,返回true: 放行,放回false,不放行
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle  目标资源方法运行前运行");
        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  视图渲染完毕后运行,最后运行");
    }
}
//仰晨study 创建时间2023/4/24 1:52 星期一
package ikun.study.config;

import ikun.study.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration //配置类
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;

    /**
     * 注册自己定义的拦截器LoginInterceptor
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**");
    }
}

 拦截器的执行流程

//仰晨study 创建时间2023/4/24 1:52 星期一
package ikun.study.config;

import ikun.study.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration //配置类
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;

    /**
     * 注册自己定义的拦截器LoginInterceptor
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)   //注册拦截器
                .addPathPatterns("/**")             //拦截全部路径    /*是一级路径/**是全部路径
                .excludePathPatterns("/login");     //放行/login路径

    }
}
//仰晨study 创建时间2023/4/24 1:45 星期一
package ikun.study.interceptor;

import com.alibaba.fastjson.JSONObject;
import ikun.study.pojo.Result;
import ikun.study.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override   //目标资源方法运行前运行,返回true: 放行,放回false,不放行
    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
        System.out.println("preHandle  目标资源方法运行前运行");


//        //1.获取请求URL
//        String url = req.getRequestURI();
//        log.info("请求的URL为:{}",url);
//
//        //2.判断请求头是否包含登录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   -=》阿里巴巴fastJSON
            String notLogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return false;
        }

        //5.解析token 如果解析失败就返回错误结果(未登录)
        try {
            JwtUtils.parseJWT(jwt);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("解析令牌失败,返回未登录错误信息");
            Result error = Result.error("NOT_LOGIN");
            //手动转换--》对象-》json   -=》阿里巴巴fastJSON
            String notLogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            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  视图渲染完毕后运行,最后运行");
    }
}

异常处理

 

//仰晨study 创建时间2023/4/24 20:41 星期一
package ikun.study.exception;

import ikun.study.pojo.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**全局异常处理器*/
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)  //捕获所有异常
    public Result ex(Exception exception) {
        exception.printStackTrace();
        return Result.error("ikun:对不起,操作失败,请联系管理员");
    }
}

 spring事务

 

 

 

 

# spring事务管理日志开关
logging:
  level:
    org.springframework.jdbc.support.JdbcTransactionManager: debug
    /**
     * Transactional:Spring事务管理(类,接口,方法都可以用(推荐,因为简单的增删改查都是不需要的))(下面的数据库方法 要么全部成功(自动提交)要么全部失败(自动回滚))
     */
    @Transactional
    @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);      //根据ID删除部门
        //int i = 1/0;
        empMapper.deleteByDeptId(id);   //根据部门id删除该部门下的员工信息

事务进阶 

事务的回滚

1/0是运行是异常

    /**
     * Transactional:Spring事务管理(类,接口,方法都可以用(推荐,因为简单的增删改查都是不需要的))(下面的数据库方法 要么全部成功(自动提交)要么全部失败(自动回滚))
     * <p>
     * `@Transactional(rollbackFor)` 是 Spring 框架中用来配置事务回滚行为的注解,其中 `rollbackFor` 属性指定了哪些异常需要回滚事务。[(<a href="https://www.marcobehler.com/guides/spring-transaction-management-transactional-in-depth">[1]</a>)][(<a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Transactional.html">[2]</a>)][(<a href="https://www.jianshu.com/p/c5988db897fc">[3]</a>)][(<a href="https://www.baeldung.com/transaction-configuration-with-jpa-and-spring">[4]</a>)]
     * 默认情况下,`@Transactional` 注解只会在遇到运行时异常或 Error 时回滚事务。但是对于一些非运行时异常,默认是不回滚事务的。而通过 `rollbackFor` 属性,我们可以指定一些特定的异常类型,使得其发生时事务也会回滚。需要注意的是,`rollbackFor` 属性默认值为空数组,表示不指定任何需要回滚的异常类型。如果设置为某个异常类型的 Class 对象,表示只有该异常发生时才会回滚事务;如果设置为多个异常类型的 Class 对象数组,表示这些异常发生时都会回滚事务。
     */
    @Transactional(rollbackFor = Exception.class)   //默认情况下只有运行时异常才会被回滚 rollbackFor指定所有异常都回滚
    @Override
    public void delete(Integer id) throws Exception {
        deptMapper.deleteById(id);      //根据ID删除部门
        //int i = 1/0;
        if (true) {
            throw new Exception("ikun:错错错是我的错");
        }
        empMapper.deleteByDeptId(id);   //根据部门id删除该部门下的员工信息

    }

事务的传播行为

 

 如果是默认值的话,那么虽然执行了finalli,但是因为一除零这个错误要回滚,所以他执行之后他也最终会回滚。所以必须要创建一个新的事务。

 事务传播行为场景

 AOP

 

        <!--AOP依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
  
        </dependency>
//仰晨study 创建时间2023/4/25 3:20 星期二
package com.itheima.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Component
@Aspect     //AOP类
@Slf4j
public class TimeAspect {

    @Around("execution(* com.itheima.service.*.*(..))")     //切入点表达式
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
        //1、记录开始时间
        long begin = System.currentTimeMillis();

        //2、调用原始方法运行
        Object result = joinPoint.proceed();

        //3、记录结束时间,计算方法耗时
        long end = System.currentTimeMillis();
        log.info(joinPoint.getSignature() + "方法耗时:{}ms",end-begin);
        return result;
    }
}

 AOP基础核心概念

 

 

AOP进阶 

 

 

 

//仰晨study 创建时间2023/4/25 3:20 星期二
package com.itheima.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect     //AOP类
@Slf4j
public class MyAspect {
    /**
     * 把切入点表达式抽取出来
     */
    @Pointcut("execution(* com.itheima.service.*.*(..))")
    public void pt() {
    }

    @Before("pt()")
    public void before() {
        log.info("Before....");
    }

    @Around("pt()")
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("Around before ...");

        //2、调用原始方法运行
        Object result = joinPoint.proceed();

        log.info("Around after ...");
        return result;
    }

    @After("pt()")
    public void after() {
        log.info("After....");
    }

    @AfterReturning("pt()")
    public void afterReturning() {
        log.info("AfterReturning....");
    }

    @AfterThrowing("pt()")
    public void afterThrowing() {
        log.info("AfterThrowing....");
    }


}

 AOP通知顺序

下面给出一些常用的切入点表达式的 demo:

- 匹配所有 public 方法:


@Pointcut("execution(public * *(*))")
 

- 匹配所有名称以 "save" 开头的方法:


@Pointcut("execution(* save*(..))")
 

- 匹配 ProductService 接口上的所有方法:


@Pointcut("execution(* com.example.ProductService.*(..))")
 

- 匹配 Person 类上所有非 private 方法:


@Pointcut("execution(public * com.example.Person.*(..))")
 

- 匹配所有返回类型为 String 的方法:


@Pointcut("execution(public String *(..))")
 

需要注意的是,这些表达式只是常见的示例,实际应用中可能还需要根据具体业务场景进行定制化的表达式编写。同时,不同的 AOP 框架对于切入点表达式的支持也可能略有不同,具体情况可以参考框架文档进行了解。

切入点表达式 

 

 

 

 

 

 连接点

//仰晨study 创建时间2023/4/25 14:34 星期二
package com.itheima.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**学习连接点*/
@Aspect //切面类
@Slf4j
@Component
public class Demo2Aspect {


    @Pointcut("execution(* com.itheima.service.DeptService.*(..))")
    private void pt() {}


    @Before("pt()")
    public void before(JoinPoint joinPoint) {
        log.info("Demo2Aspect...before...");
    }

    @Around("pt()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("Demo2Aspect...Around-before...");

        //1.获取目标对象的类名
        String name = joinPoint.getTarget().getClass().getName();
        log.info("目标对象的类名:{}", name);

        //2.获取目标方法的方法名
        String methodName = joinPoint.getSignature().getName();
        log.info("目标对象的方法名:{}",methodName);

        //3.获取目标方法运行时传入的参数
        Object[] args = joinPoint.getArgs();
        log.info("目标方法运行时传入的参数:{}", Arrays.toString(args));

        //4.目标方法执行  无参就好  有参就吧获取到的参数在放回去就好了
        Object result = joinPoint.proceed();

        //5.获取目标方法运行的返回值
        log.info("目标方法运行的返回值:{}",result);


        log.info("Demo2Aspect...Around-after...");
        return result;
    }
}

案例

 

 

//仰晨study 创建时间2023/4/25 20:41 星期二
package ikun.study.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 用来面向切面的标记注解
 */
@Retention(RetentionPolicy.RUNTIME) //运行时有效
@Target(ElementType.METHOD)         //允许写在方法上
public @interface Log {
}
//仰晨study 创建时间2023/4/25 20:45 星期二
package ikun.study.aop;

import com.alibaba.fastjson.JSONObject;
import ikun.study.mapper.OperateLogMapper;
import ikun.study.pojo.OperateLog;
import ikun.study.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;

@Slf4j
@Component
@Aspect     //切面类
public class LogAspect {
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private OperateLogMapper operateLogMapper;

    @Around("@annotation(ikun.study.anno.Log)")
    public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
        //操作人ID-当前员工id
        //----获取jwt令牌,解析令牌
        String jwt = request.getHeader("token");
        Claims claims = JwtUtils.parseJWT(jwt);
        Integer operateUser = (Integer) claims.get("id");

        //操作时间
        LocalDateTime operateTime = LocalDateTime.now();

        //操作类名
        String className = joinPoint.getTarget().getClass().getName();

        //操作方法名
        String methodName = joinPoint.getSignature().getName();

        //操作方法参数
        Object[] args = joinPoint.getArgs();
        String methodParams = Arrays.toString(args);

        long begin = System.currentTimeMillis();
        //调用原始方法
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();

        //方法返回值
        String returnValue = JSONObject.toJSONString(result);

        //操作时间
        Long countTime = end - begin;


        //记录操作日志
        OperateLog operateLog = new OperateLog(null,operateUser,operateTime,className,methodName,methodParams,returnValue,countTime);
        operateLogMapper.insert(operateLog);

        log.info("AOP记录操作日志:{}",operateLog);

        return result;
    }
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值