《 SpringBoot经典学习笔记》读书笔记

一SpringBoot返回Json数据及数据封装

项目开发中,接口和接口之间,前后端之间数据传输使用Json格式,
在SpringBoot中的Controller使用@RestController注解即可返回Json格式的数据,
点击进入@RestController注解
在这里插入图片描述
在这里插入图片描述
可以看出@RestController注解包含了原来的@Controller@ResponseBody注解
@ResponseBody将返回的数据结构转换为json格式


打开idea右侧的maven栏
在这里插入图片描述
发现在此版本中SpringBoot的默认json解析框架是jackson

1.1Jackson对null的处理

比如期望所有的null在转json时变成"""这样的空字符串,
在SpringBoot中做以下配置即可

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import java.io.IOException;

/**
 * 使用阿里巴巴的fastJson时,把jackson的配置注释掉
 */
@Configuration
public class JacksonConfig {
    @Bean
    @Primary
    @ConditionalOnMissingBean(ObjectMapper.class)
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                jsonGenerator.writeString("");
            }
        });
        return objectMapper;
    }
}

在这里插入图片描述
发现null成功替换成了""

1.2fastJson对null的处理

继承WebMVCConfigurationSupport,覆盖其configureMessageConverters方法
配置如下:

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class fastJsonConfig extends WebMvcConfigurationSupport {

    /**
     * 使用阿里 FastJson 作为JSON MessageConverter
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(
                // 保留map空的字段
                SerializerFeature.WriteMapNullValue,
                // 将String类型的null转成""
                SerializerFeature.WriteNullStringAsEmpty,
                // 将Number类型的null转成0
                SerializerFeature.WriteNullNumberAsZero,
                // 将List类型的null转成[]
                SerializerFeature.WriteNullListAsEmpty,
                // 将Boolean类型的null转成false
                SerializerFeature.WriteNullBooleanAsFalse,
                // 避免循环引用
                SerializerFeature.DisableCircularReferenceDetect);

        converter.setFastJsonConfig(config);
        converter.setDefaultCharset(Charset.forName("UTF-8"));
        List<MediaType> mediaTypeList = new ArrayList<>();
        // 解决中文乱码问题,相当于在Controller上的@RequestMapping中加了个属性produces = "application/json"
        mediaTypeList.add(MediaType.APPLICATION_JSON);
        converter.setSupportedMediaTypes(mediaTypeList);
        converters.add(converter);




        //Long转json精度丢失的配置
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new
                MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(jackson2HttpMessageConverter);
    }
}

1.3封装统一返回的数据结构

在实际项目中,除了要封装数据之外,需要在返回的json中添加例如状态码code,一些msg给调用者

import lombok.Data;
import lombok.experimental.Accessors;
import java.util.HashMap;
import java.util.Map;

@Data
@Accessors(chain = true)//开启链式操作,R.ok().setData(map);
public class R {
    private Integer code;
    private String message;
    private Map<String,Object> data = new HashMap<>();

    public static R ok(){
        R r = new R();
        r.setCode(0);
        r.setMessage("成功");
        return r;
    }

    public static R error(){
        R r = new R();
        r.setCode(-1);
        r.setMessage("失败");
        return r;
    }
    
    public R data(String key,Object value){
        this.data.put(key,value);
        return this;
    }
}

二SpringBoot使用是slf4j进行日志记录

application.yml中写入如下

logging:
  config: course03使用slf4j进行日志记录/logback.xml # 指定项目启动时,读取哪个配置文件, 这里指的是 根目录下的logback.xml
  level:
    com.itcodai.course03.dao: trace # 此包下的日志级别为 trace

根目录下写入slf4j的配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <!-- 格式化输出:%date表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
    <property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />

    <!-- 定义日志存储的路径,不要配置相对路径 -->
    <property name="FILE_PATH" value="D:/logs/course03/demo.%d{yyyy-MM-dd}.%i.log" />

    <!-- 控制台输出日志 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- 按照上面配置的LOG_PATTERN来打印日志 -->
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!--每天生成一个日志文件,保存15天的日志文件。rollingFile是用来切分文件的 -->
    <appender name="FILE"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${FILE_PATH}</fileNamePattern>
            <!-- keep 15 days' worth of history -->
            <maxHistory>15</maxHistory>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- 日志文件的最大大小 -->
                <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>

        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>
    <!-- project default level -->
    <!--  常用的日志级别按照从高到低依次为:ERROR、WARN、INFO、DEBUG。  -->
    <logger name="com.itcodai.course03" level="DEBUG" />

    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

心态泵了我写到第7课了中午睡觉,下午没了

三SpringBoot项目属性配置

3.1读取配置信息

@value(value="") 获取指定配置文件信息
@ConfigurationProperties(prefix="")获取以指定前置开头的配置信息

使用@ConfigurationProperties(prefix="")
1.写application.yml配置

# 配置多个微服务的地址
url:
   # 订单微服务的地址
   orderUrl: http://localhost:8002
   # 用户微服务的地址
   userUrl: http://localhost:8003
   # 购物车微服务的地址
   shoppingUrl: http://localhost:8004

2.定义接收实体类

@Component
@ConfigurationProperties(prefix = "url")
public class MicroServiceUrl {

   private String orderUrl;
   private String userUrl;
   private String shoppingUrl;
}

3.引入maven坐标

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>

4.编写controller读取并使用配置信息

@RestController
@RequestMapping("/test")
public class ConfigController {

   private static final Logger LOGGER = LoggerFactory.getLogger(ConfigController.class);

   @Value("${url.orderUrl}")
   private String orderUrl;

   @Resource
   private MicroServiceUrl microServiceUrl;

   @RequestMapping("/config")
   public String testConfig() {
       LOGGER.info("=====获取的订单服务地址为:{}", orderUrl);
       // 使用配置类来获取
       LOGGER.info("=====获取的订单服务地址为:{}", microServiceUrl.getOrderUrl());
       LOGGER.info("=====获取的用户服务地址为:{}", microServiceUrl.getUserUrl());
       LOGGER.info("=====获取的购物车服务地址为:{}", microServiceUrl.getShoppingUrl());
       return "success";
   }
}

5.控制台打印结果

在这里插入图片描述

3.2指定配置文件

例如我们有两个配置文件 application-dev.ymlapplication-pro.yml
对应开发环境和生产环境

在这里插入图片描述
在这里插入图片描述
application.yml中指定读取哪个配置文件的信息
在这里插入图片描述

四SpringBoot中的MVC支持

4.1@RestController

@RestController可以看做是@Controller@ResponseBody的结合体

注意:
前后端分离时,可以用@RestController返回json数据给前端
不是前后端分离,由于@RestController将user当做字符串返回所以不可以使用,
只能使用@Controller来跳转页面
在这里插入图片描述

4.2@RequestMapping

处理请求地址的注解,可以用在类上或方法上
常用属性

  • value:指定请求的实际地址
  • method:指定请求的类型,主要有 GET、PUT、POST、DELETE,默认为 GET
  • produces:指定返回内容类型,如 produces = “application/json; charset=UTF-8”

4.3@PathVariable

获取url参数,当url中的参数和方法接收的参数不一样时需要通过value属性来指定对应关系

4.4@RequestParam

获取url参数
@RequestParam获取http://localhost:8080/user?id=1中的参数
@PathVariable获取ttp://localhost:8080/user/{id} 中的参数

  • value指定url参数和方法接收参数的对应关系
  • required为true表示该参数比传,否则抛出404
  • defaultValue默认值,表示如果请求中没有同名参数时的默认值

4.5@RequestBody

接收前端传递的实体对象

五SpringBoot集成swagger

点击进入SpringBoot集成swagger

六SpringBoot全局异常处理

6.1定义返回统一json结构


@Data
//开启链式操作
@Accessors(chain = true)
public class R {
    private Integer code;
    private String message;
    private Map<String,Object> data = new HashMap<>();

    public static R ok(){
        R r = new R();
        r.setCode(0);
        r.setMessage("成功");
        return r;
    }

    public static R error(){
        R r = new R();
        r.setCode(-1);
        r.setMessage("失败");
        return r;
    }

    public static R come(){
        R r = new R();
        r.setCode(-1);
        r.setMessage("失败");
        return r;
    }

    public R data(String key,Object value){
        this.data.put(key,value);
        return this;
    }
}

6.2处理系统异常

新建一个GlobalExceptionHandler全局异常处理类
加上@ControllerAdvice注解即可拦截项目中抛出的异常

@ControllerAdvice注解包含了@Component注解
说明SpringBoot启动时,该类会交给Spring管理

  • basePackages属性指定拦截哪个包下的异常信息,默认
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
}

在方法上加@ExceptionHandler指定具体的异常
在方法中处理该异常,
通过统一的json结构体返回给调用者

    /**
     * 空指针异常
     * @param ex NullPointerException
     * @return
     */
    @ExceptionHandler(NullPointerException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public JsonResult handleTypeMismatchException(NullPointerException ex) {
        logger.error("空指针异常,{}", ex.getMessage());
        return new JsonResult("500", "空指针异常了");
    }

七SpringBoot中的AOP处理

面向切面编程

低耦合,易扩展,避免重复

1.引入坐标

		<dependency>
   		<groupId>org.springframework.boot</groupId>
   		<artifactId>spring-boot-starter-aop</artifactId>
   	</dependency>

2.实现AOP切面
@Aspect声明一个类为切面类,作用于类上

@Aspect
@Component
public class LogAspectHandler {
}

3.@Pointcut
@Pointcut定义一个切面

  • execution属性 ,拦截某包下的方法
@Aspect
@Component
public class LogAspectHandler {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 定义一个切面,拦截com.itcodai.course09.controller包下的所有方法
     */
    @Pointcut("execution(* com.itcodai.course09.controller..*.*(..))")
    public void pointCut() {}


  • @annontation属性,针对某个注解定义切面
//针对@GetMapping方法做切面
@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
public void annotationCut() {}

4.其它注解

  • @Before 在做某件事之前做的事。
  • @After:在做某件事之后做的事。
  • @AfterReturning:在做某件事之后,对其返回值做增强处理。
  • @AfterThrowing:在做某件事抛出异常时,处理。

八SpringBoot集成MyBatis

1.引入坐标

		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>

2.properties.yml配置

# 服务端口号
server:
  port: 8080

# 数据库地址
datasource:
  url: localhost:3306/blog_test

spring:
  datasource: # 数据库配置
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://${datasource.url}?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10
    username: root
    password: 123456
    hikari: # SpringBoot的默认数据库连接池
      maximum-pool-size: 10 # 最大连接池数
      max-lifetime: 1770000

mybatis:
  # 指定别名设置的包为所有entity
  type-aliases-package: com.itcodai.course10.entity
  configuration:
    map-underscore-to-camel-case: true # 驼峰命名规范
  mapper-locations: # mapper映射文件位置
    - classpath:mapper/*.xml

3.注解
@Mapper放在Mapper类上
@MapperScan放在启动类上,value属性指定扫描的包位置
@Param指定参数
@Result指定实体类属性和数据库表的对应关系

@Select("select * from user where id = #{id}")
@Results({
	@Result(property = "username", column = "user_name"),
	@Result(property = "password", column = "password")
})
User getUser(Long id);

九SpringBoot事务配置管理

1.导入坐标

<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
		<artifactId>mybatis-spring-boot-starter</artifactId>
		<version>1.3.2</version>
</dependency>

2.编写mapper


public interface UserMapper {

    @Insert("insert into user (user_name, password) values (#{username}, #{password})")
    Integer insertUser(User user);
}

3.编写Server

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Override
    @Transactional
    public void isertUser(User user) {
        // 插入用户信息
        userMapper.insertUser(user);
        // 手动抛出异常
        throw new RuntimeException();
    }
}

4.编写controller

@RestController
public class TestController {

    @Resource
    private UserService userService;

    /**
     * 正常测试
     * @param user
     * @return
     */
    @PostMapping("/adduser")
    public String addUser(@RequestBody User user) throws Exception {
        if (null != user) {
            userService.isertUser(user);
            return "success";
        } else {
            return "false";
        }
    }
}

5.注解
@Transactional 开启事务管理
注意
SpringBoot默认事务规则是遇到 运行时异常错误才会回滚
针对非运行时异常,需要属性rollbackFor
@Transactional(rollbackFor = Execption.class)

当我们使用try…catch时,事务是不会回滚的,尽量上抛异常

在使用synchronized是,需要保证锁的范围和事务的范围大,即
在调用该Server的地方加锁,保证锁的范围大于事务的范围

九SpringBoot监听器

web监听器是一种Servlet的特殊类
用来监听特定事件

十SpringBoot拦截器

十一SpringBoot集成Redis

1.引入坐标

	<dependencies>
		<!--redis-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
        <!--阿里巴巴fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.35</version>
        </dependency>

2.redis配置

server:
  port: 8080

# 数据库地址
datasource:
  url: localhost:3306/blog_test

spring:
  datasource: # 数据库配置
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://${datasource.url}?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10
    username: root
    password: 123456
    hikari:
      maximum-pool-size: 10 # 最大连接池数
      max-lifetime: 1770000

mybatis:
  # 指定别名设置的包为所有entity
  type-aliases-package: com.itcodai.course16.entity
  configuration:
    map-underscore-to-camel-case: true # 驼峰命名规范
  mapper-locations: # mapper映射文件位置
    - classpath:mapper/*.xml

SpringBoot对redis有两个模板:RedisTemplate和StringRedisTemplate

RedisTemplate

RedisTemplate<K,V>模板类在操作redis时默认使用JdkSerializationRedisSerializer序列化
所以在存储时会出现乱码
点击进入乱码的原因
所以需要修改默认的序列化方式


private RedisTemplate redisTemplate;
@Autowired(required = false)
public void setRedisTemplate(RedisTemplate redisTemplate) {
    RedisSerializer stringSerializer = new StringRedisSerializer();
    redisTemplate.setKeySerializer(stringSerializer);
    redisTemplate.setValueSerializer(stringSerializer);
    redisTemplate.setHashKeySerializer(stringSerializer);
    redisTemplate.setHashValueSerializer(stringSerializer);
    this.redisTemplate = redisTemplate;
}

StringRedisTemplate

StringRedisTemplate不会出现中文乱码,直接注入使用即可

十二SpringBoot集成MQ

十三SpringBoot集成Shiro

Shiro是解决 认证,授权,加密,会话管理,与Web集成,缓存
在这里插入图片描述

图为: Shiro的组件图

13.1Shiro的工作流程

一个Shiro应用的工作流程:

  1. 在Subject的login(token)方法里传入代表用户身份和凭证的AuthenticationToken实例
  2. 而Subject又委托给SecurityManager;
      1. 我们给Shiro的安全管理器注入域,从而让安全管理器得到合法的用户及其权限来判断

Shiro不提供维护用户/权限,而是需要开发人员注入 到域中
在这里插入图片描述

图为: Shiro 的工作流程

13.2权限认证

权限认证的核心三要素
权限
角色
用户
在这里插入图片描述

图为:权限用户角色的关系图

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值