栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot-常见场景(下)-三更补充版

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力
接上文(准备开始前后端分离的模式) 准备工作:https://www.bilibili.com/video/BV1T54y1n7PB?p=43 基本测试(数据库查询–可跳过,与springMVC整合步骤基本一致)

因为是前后端分离的项目,所以最终方法的返回值都会放到请求体当中—>@RestController
所有文件与之前测试的相同

实体类

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

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String username;
    private Integer age;
    private String address;
}




记得加注解,才会知道这个是个mapper接口


接口相应格式统一(另一项目的)



前端发送请求代码编写

出现了跨域问题

4.5 跨域请求 4.5.1 什么是跨域

​ 浏览器出于安全的考虑,使用 XMLHttpRequest对象发起 HTTP请求时必须遵守同源策略,否则就是跨域的HTTP请求,默认情况下是被禁止的。 同源策略要求源相同才能正常进行通信,即协议、域名、端口号都完全一致。

4.5.2 CORS解决跨域

​ CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing),允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

​ 它通过服务器增加一个特殊的Header[Access-Control-Allow-Origin]来告诉客户端跨域的限制,如果浏览器支持CORS、并且判断Origin通过的话,就会允许XMLHttpRequest发起跨域请求。

4.5.3 SpringBoot使用CORS解决跨域 1.使用@CrossOrigin

可以在支持跨域的方法上或者是Controller上加上@CrossOrigin注解

@RestController
@RequestMapping("/user")
@CrossOrigin
public class UserController {

    @Autowired
    private UserServcie userServcie;

    @RequestMapping("/findAll")
    public ResponseResult findAll(){
        //调用service查询数据 ,进行返回
        List users = userServcie.findAll();

        return new ResponseResult(200,users);
    }
}


2.使用 WebMvcConfigurer 的 addCorsMappings 方法配置CorsInterceptor(更好的方式)
@Configuration   //表所示为配置类
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
      // 设置允许跨域的路径
        registry.addMapping("
public class JwtUtil {

    //有效期为
    public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000  一个小时
    //设置秘钥明文
    public static final String JWT_KEY = "sangeng";

    
    public static String createJWT(String id, String subject, Long ttlMillis) {

        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        if(ttlMillis==null){
            ttlMillis=JwtUtil.JWT_TTL;
        }
        long expMillis = nowMillis + ttlMillis;
        Date expDate = new Date(expMillis);
        SecretKey secretKey = generalKey();

        JwtBuilder builder = Jwts.builder()
                .setId(id)              //唯一的ID
                .setSubject(subject)   // 主题  可以是JSON数据
                .setIssuer("sg")     // 签发者
                .setIssuedAt(now)      // 签发时间
                .signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
                .setExpiration(expDate);// 设置过期时间
        return builder.compact();
    }

    
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }
    
    
    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
    }


}

乱写就会抛出异常

4.6.0.3 登录接口实现

数据准备

DROp TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;



insert  into `sys_user`(`id`,`username`,`password`) values (1,'root','root'),(2,'sangeng','caotang');


实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class SystemUser {

    private Integer id;
    private String username;
    private String password;
}

SystemUserController

import com.sangeng.domain.ResponseResult;
import com.sangeng.domain.SystemUser;
import com.sangeng.service.SystemUserService;
import com.sangeng.utils.JwtUtil;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
@RequestMapping("/sys_user")
public class SystemUserController {
    @Autowired
    private SystemUserService userService;

    @PostMapping("/login")
    public ResponseResult login(@RequestBody SystemUser user) {
        //校验用户名密码是否正确
        SystemUser loginUser = userService.login(user);
        Map map;
        if (loginUser != null) {
            //如果正确 生成token返回
            map = new HashMap<>();
            String token = JwtUtil.createJWT(UUID.randomUUID().toString(), String.valueOf(loginUser.getId()), null);
            map.put("token", token);
        } else {
            //如果不正确 给出相应的提示
            return new ResponseResult(300, "用户名或密码错误,请重新登录");
        }
        return new ResponseResult(200, "登录成功", map);
    }
}

Service

public interface SystemUserService {

    public SystemUser login(SystemUser user);
}
@Service
public class SystemUserServcieImpl implements SystemUserService {
    @Autowired
    private SystemUserMapper systemUserMapper;

    @Override
    public SystemUser login(SystemUser user) {
        SystemUser loginUser = systemUserMapper.login(user);
        return loginUser;
    }
}

dao

@Mapper
@Repository
public interface UserMapper {
    List findAll();
}




    

4.6.0.4 登录页面

   
   
   
   
   
   
   BeAdmin - Bootstrap Admin Theme
   
   
   
   
   
   
   
   
   
   
   
   
   
   



   
   

Image

SIGN IN TO CONTINUE.

4.6.1 拦截器的概念(和MVC基本无异)

​ 如果我们想在多个Handler方法执行之前或者之后都进行一些处理,甚至某些情况下需要拦截掉,不让Handler方法执行。那么可以使用SpringMVC为我们提供的拦截器。

​ 详情见 https://space.bilibili.com/663528522 SpringMVC课程中拦截器相关章节。

4.6.1 使用步骤 ①创建类实现HandlerInterceptor接口
public class LoginInterceptor implements HandlerInterceptor {
}
②实现方法
@Component  //把类放到spring容器里面,底下为相应的业务逻辑
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取请求头中的token
        String token = request.getHeader("token");
        //判断token是否为空,如果为空也代表未登录 提醒重新登录(401)
        if(!StringUtils.hasText(token)){
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        //解析token看看是否成功
        try {
            Claims claims = JwtUtil.parseJWT(token);
            String subject = claims.getSubject();
            System.out.println(subject);
        } catch (Exception e) {
            e.printStackTrace();
            //如果解析过程中没有出现异常说明是登录状态
            //如果出现了异常,说明未登录,提醒重新登录(401)
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        return true;
    }
}
③配置拦截器
@Configuration
public class LoginConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)//添加拦截器
            .addPathPatterns("/**")  //配置拦截路径
            .excludePathPatterns("/sys_user/login");//配置排除路径
    }
}

4.7 异常统一处理(整合MVC的) ①创建类加上@ControllerAdvice注解进行标识
@ControllerAdvice
public class MyControllerAdvice {

}
②定义异常处理方法

​ 定义异常处理方法,使用 @ExceptionHandler 标识可以处理的异常。

@ControllerAdvice
public class MyControllerAdvice {

    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public ResponseResult handlerException(Exception e){
        //获取异常信息,存放如ResponseResult的msg属性
        String message = e.getMessage();
        ResponseResult result = new ResponseResult(300,message);
        //把ResponseResult作为返回值返回,要求到时候转换成json存入响应体中
        return result;
    }
}

4.8 获取web原生对象

​ 我们之前在web阶段我们经常要使用到request对象,response,session对象等。我们也可以通过SpringMVC获取到这些对象。(不过在MVC中我们很少获取这些对象,因为有更简便的方式,避免了我们使用这些原生对象相对繁琐的API。)

​ 我们只需要在方法上添加对应类型的参数即可,但是注意数据类型不要写错了,SpringMVC会把我们需要的对象传给我们的形参。

@RestController
public class TestController {

    @RequestMapping("/getRequestAndResponse")
    public ResponseResult getRequestAndResponse(HttpServletRequest request, HttpServletResponse response, HttpSession session){
        System.out.println(request);
        return new ResponseResult(200,"成功");
    }
}

4.9 自定义参数解析


所有方法都用,这样就很麻烦。

​ 如果我们想实现像获取请求体中的数据那样,在Handler方法的参数上增加一个@RepuestBody注解就可以获取到对应的数据的话。

​ 可以使用HandlerMethodArgumentResolver来实现自定义的参数解析。

新建一个resolver包

①定义用来标识的注解

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUserId {

}

②创建类实现HandlerMethodArgumentResolver接口并重写其中的方法

注意加上@Component注解注入Spring容器

@Component
public class UserIdArgumentResolver implements HandlerMethodArgumentResolver {

    //判断方法参数使用能使用当前的参数解析器进行解析
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        //如果方法参数有加上CurrentUserId注解,就能把被我们的解析器解析
        return parameter.hasParameterAnnotation(CurrentUserId.class);
    }
    //进行参数解析的方法,可以在方法中获取对应的数据,然后把数据作为返回值返回。方法的返回值就会赋值给对应的方法参数
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        //获取请求头中的token
        String token = webRequest.getHeader("token");
        if(StringUtils.hasText(token)){
            //解析token,获取userId
            Claims claims = JwtUtil.parseJWT(token);
            String userId = claims.getSubject();
            //返回结果
            return userId;
        }
        return null;
    }
}

③配置参数解析器,因为HandlerMethodArgumentResolver 这种参数解析器属于MVC中的主键,我们要进行主键相关的配置。就像之前的

@Configuration
public class ArgumentResolverConfig implements WebMvcConfigurer {

    @Autowired
    private UserIdArgumentResolver userIdArgumentResolver;

    @Override
    public void addArgumentResolvers(List resolvers) {
        resolvers.add(userIdArgumentResolver);
    }
}

④测试

在需要获取UserId的方法中增加对应的方法参数然后使用@CurrentUserId进行标识即可获取到数据

@RestController
@RequestMapping("/user")
//@CrossOrigin
public class UserController {

    @Autowired
    private UserServcie userServcie;

    @RequestMapping("/findAll")
    public ResponseResult findAll(@CurrentUserId String userId) throws Exception {
        System.out.println(userId);
        //调用service查询数据 ,进行返回s
        List users = userServcie.findAll();

        return new ResponseResult(200,users);
    }
}
4.10 声明式事务

​ 直接在需要事务控制的方法上加上对应的注解**@Transactional**

记得加在service层,因为是service层调用mapper对数据库操作(业务层才涉及到事务)

@Service
public class UserServiceImpl implements UserServcie {

    @Autowired
    private UserMapper userMapper;

    @Override
    public List findAll() {
        return userMapper.findAll();
    }

    @Override
    @Transactional
    public void insertUser() {
        //添加2个用户到数据库
        User user = new User(null,"sg666",15,"上海");
        User user2 = new User(null,"sg777",16,"北京");
        userMapper.insertUser(user);
        System.out.println(1/0);
        userMapper.insertUser(user2);
    }


}
4.11 AOP(与spring一模一样,只是不用去配置)

​ AOP详细知识学习见:https://space.bilibili.com/663528522 中的Spring教程

​ 在SpringBoot中默认是开启AOP功能的。如果不想开启AOP功能可以使用如下配置设置为false

spring:
  aop:
    auto: false
4.11.1 使用步骤

①添加依赖

        
            org.springframework.boot
            spring-boot-starter-aop
        

②自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InvokeLog {
}

③定义切面类

@Aspect  //标识这是一个切面类
@Component
public class InvokeLogAspect {

    //确定切点
    @Pointcut("@annotation(com.sangeng.aop.InvokeLog)")
    public void pt(){
    }

    @Around("pt()")
    public Object printInvokeLog(ProceedingJoinPoint joinPoint){
        //目标方法调用前
        Object proceed = null;
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getMethod().getName();
        System.out.println(methodName+"即将被调用");
        try {
            proceed = joinPoint.proceed();
            //目标方法调用后
            System.out.println(methodName+"被调用完了");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            //目标方法出现异常了
            System.out.println(methodName+"出现了异常");
        }
        return proceed;
    }
}

④在需要正确的地方增加对应的注解

@Service
public class UserServiceImpl implements UserServcie {

    @Autowired
    private UserMapper userMapper;

    @Override
    @InvokeLog  //需要被增强方法需要加上对应的注解
    public List findAll() {
        return userMapper.findAll();
    }
}
4.11.2 切换动态代理

​ 有的时候我们需要修改AOP的代理方式。

​ 我们可以使用以下方式修改:

​ 在配置文件中配置spring.aop.proxy-target-class为false这为使用jdk动态代理。该配置默认值为true,代表使用cglib动态代理。

@SpringBootApplication
@EnableAspectJAutoProxy(proxyTargetClass = false)//修改代理方式
public class WebApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(WebApplication.class, args);
    }
}

​ 如果想生效还需要在配置文件中做如下配置

spring:
  aop:
    proxy-target-class: false #切换动态代理的方式
4.12 模板引擎相关-Thymeleaf 4.12.1 快速入门 4.12.1.1依赖
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
4.12.1.2定义Controller

在controller中往域中存数据,并且跳转

@Controller
public class ThymeleafController {

    @Autowired
    private UserServcie userServcie;

    @RequestMapping("/thymeleaf/users")
    public String users(Model model){
        //获取数据
        List users = userServcie.findAll();
        //望域中存入数据
        model.addAttribute("users",users);
        model.addAttribute("msg","hello thymeleaf");
        //页面跳转
        return "table-standard";
    }
}
4.12.1.3 htmL

在resourcestemplates下存放模板页面。

在html标签中加上 xmlns:th=“http://www.thymeleaf.org”

获取域中的name属性的值可以使用: ${name} 注意要在th开头的属性中使用


 .....
 
Kitchen Sink

如果需要引入静态资源,需要使用如下写法。

   
   
   
   
   
   
   
   
   
   
   
   
   

遍历语法:遍历的语法 th:each=“自定义的元素变量名称 : ${集合变量名称}”


    
    
    
    

5.整合Redis ①依赖
        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        
②配置Redis地址和端口号
spring:
  redis:
    host: 127.0.0.1 #redis服务器ip地址
    port: 6379  #redis端口号
③注入RedisTemplate使用
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Test
    public void testRedis(){
        redisTemplate.opsForValue().set("name","三更");
    }
6.环境切换 6.1 为什么要使用profile

​ 在实际开发环境中,我们存在开发环境的配置,部署环境的配置,测试环境的配置等等,里面的配置信息很多时,例如:端口、上下文路径、数据库配置等等,若每次切换环境时,我们都需要进行修改这些配置信息时,会比较麻烦,profile的出现就是为了解决这个问题。它可以让我们针对不同的环境进行不同的配置,然后可以通过激活、指定参数等方式快速切换环境。

6.2 使用 6.2.1 创建profile配置文件

​ 我们可以用application-xxx.yml的命名方式 创建配置文件,其中xxx可以根据自己的需求来定义。

​ 例如

​ 我们需要一个测试环境的配置文件,则可以命名为:application-test.yml

​ 需要一个生产环境的配置文件,可以命名为:application-prod.yml

​ 我们可以不同环境下不同的配置放到对应的profile文件中进行配置。然后把不同环境下都相同的配置放到application.yml文件中配置。

6.2.2 激活环境

​ 我们可以再application.yml文件中使用spring.profiles.active属性来配置激活哪个环境。

​ 也可以使用虚拟机参数来指定激活环境。例如 : -Dspring.profiles.active=test

​ 也可以使用命令行参数来激活环境。例如: –spring.profiles.active =test

7.日志

​ 开启日志

debug: true #开启日志
logging:
  level:
    com.sangeng: debug #设置日志级别
8.指标监控

​ 我们在日常开发中需要对程序内部的运行情况进行监控, 比如:健康度、运行指标、日志信息、线程状况等等 。而SpringBoot的监控Actuator就可以帮我们解决这些问题。

8.1 使用

①添加依赖


 	org.springframework.boot
 	spring-boot-starter-actuator

②访问监控接口

http://localhost:81/actuator

③配置启用监控端点

management:
  endpoints:
    enabled-by-default: true #配置启用所有端点
	web:
      exposure:
        include: "*" #web端暴露所有端点
8.2 常用端点
端点名称描述
beans显示应用程序中所有Spring Bean的完整列表。
health显示应用程序运行状况信息。
info显示应用程序信息。
loggers显示和修改应用程序中日志的配置。
metrics显示当前应用程序的“指标”信息。
mappings显示所有@RequestMapping路径列表。
scheduledtasks显示应用程序中的计划任务。
8.3 图形化界面 SpringBoot Admin

①创建SpringBoot Admin Server应用

要求引入spring-boot-admin-starter-server依赖

        
            de.codecentric
            spring-boot-admin-starter-server
        

然后在启动类上加上@EnableAdminServer注解

②配置SpringBoot Admin client应用

在需要监控的应用中加上spring-boot-admin-starter-client依赖

        
            de.codecentric
            spring-boot-admin-starter-client
            2.3.1
        

然后配置SpringBoot Admin Server的地址

spring:
  boot:
    admin:
      client:
        url: http://localhost:8888 #配置 Admin Server的地址
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/881109.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号