美文网首页
spring boot学习笔记

spring boot学习笔记

作者: 大赟哥 | 来源:发表于2017-08-04 21:59 被阅读0次

    [TOC]

    spring boot

    • 特点:
      • 1、化繁为简,简化配置
      • 2、备受关注,是下一代框架
      • 3、微服务的入门级微框架

    RequestMapping若要能使用多个路径访问同一个方法,可以在value={"/hello1", "/hello2"}

    Spring-Data-Jpa:JPA定义了一系列对象持久化的标准,目前实现这一规范的产品有hibernate、TopLink等

    NOTE:
    1、前置知识:利用maven构建项目,Spring注解、RESTful API
    2.不需要去学SpringMVC
    3.Java、Maven等版本保持一致

    Springboot的创建

    在idea中用Spring Initializr进行创建

    项目配置

    方法一:
    在application.properties中添加

    <!--port代表端口号,context-path代表url前面的前缀-->
    server.port=8081
    server.context-path=/girl
    

    方法二:
    创建一个application.yml文件添加

    server:
      context-path: /girl
      port: 8082
    

    如何将配置文件中的属性注入进变量中去

    方法一:使用Value注解

    配置文件:application.yml

    server:
      port: 8080
    cupSize: B
    

    NOTE:这里cupSize属性要和server并列,不然会报错

    java文件:HelloController.java

      @Value("${cupSize}")
        private String cupSize;
    
        @RequestMapping(value = "/hello",method = RequestMethod.GET)
        public String say(){
            return cupSize;
        }
    

    @value:将配置文件中的属性值注入到属性中

    方法二:使用类对象

    配置文件: applivation.yml

    girl:
      cupSize: B
      age: 18
    

    对象类:GirlProperties

    @Component
    @ConfigurationProperties(prefix = "girl")
    public class GirlProperties {
        private  String cupSize;
        private  Integer age;
    
        public void setCupSize(String cupSize) {
            this.cupSize = cupSize;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String getCupSize() {
            return cupSize;
        }
    
        public Integer getAge() {
            return age;
        }
      }
    

    NOTE:@ConfigurationProperties(prefix = "girl"):获取前缀是girl的配置
    @Component:表示与配置文件中的信息进行匹配,把普通pojo实例化到spring容器中

    controller:

    @RestController
    public class HelloController {
    @Autowired
     private GirlProperties girlProperties;
    
        @RequestMapping(value = "/hello",method = RequestMethod.GET)
        public String say(){
            return girlProperties.getCupSize();
        }
    }
    

    多环境配置

    环境一:application-dev.yml

    server:
      port: 8080
    girl:
      cupSize: B
      age: 18
    

    环境二:application-prod.yml

    server:
      port: 8080
    girl:
      cupSize: F
      age: 18
    

    在 applicatin.yml中配置

    Spring:
        profiles:
            active:dev
    

    可以根据active的不同使用不同的环境

    Controller的使用

    @Controller:处理http请求
    @RestController: Spring4之后新加的注解,原来返回json需要@ResponseBody配合@Controller
    @RequestMapping:配置url映射

    如何处理url中的参数

    @PathVariable 获取url中的数据 (请求中为restful类型请求:/hello/${id})
    @RequestParam 获取请求参数的值 (正常请求:/hello?id=23)
    @GetMapping 组合注解 (@GetMapping(value="/say")相当于@RequestMapping(value = "/say",method = RequestMethod.GET))

    数据库操作

    Spring-Data-Jpa
    JPA(Java Persistence API):定义了一系列对象持久化的标准,目前实现这一规范的产品有Hibernate、TopLink等

    创建表

    pom.xml文件引入依赖:

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.24</version>
            </dependency>
    
    Note:mysql的版本控制,如果太高会报错
    

    application.yml文件配置数据源和jpa

      datasource:
            driver-class-name: com.mysql.jdbc.Driver
            url: jdbc:mysql://localhost:3306/dbgirl
            username: root
            password:
      jpa:
          hibernate:
               ddl-auto: create
          show-sql: true
    
    Note:datasource:连接数据库
    ddl-auto:
    creat表示不管数据库是不是有这张表都会重新创建
    update:第一次运行会创建表,以后创建如果表中有数据会保留数据
    create-drop:应用在停下来的时候会将表删除
    none:什么都不做
    validate:表中字段与实体类中对应,如果有不一样的会报错
    show-sql:显示sql语句
    

    Girl实体类:

    @Entity
    public class Girl {
        @Id
        @GeneratedValue
        private Integer id;
    
        private String cupSize;
    
        private  Integer age;
        //下面是get set方法以及空构造
    }
    

    Note:@Entity:jpa特性,表示实体类与数据库对应的表
    @Id:主键
    @GeneratedValue:自动生成

    API接口开发

    请求类型 请求路径 功能
    GET /girls 获取女生列表
    POST /girls 创建一个女生
    GET /girls/id 通过id查询一个女生
    PUT /girls/id 通过id更新一个女生
    DELETE /girls/id 通过id删除一个女生

    创建一个接口继承Jpa

    public interface GirlRepository extends JpaRepository<Girl,Integer>{
    
        //通过年龄来查询
        public List<Girl> findByAge(Integer age);
    }
    

    创建出controller

    @RestController
    public class GirlController{
    
        @Autowired
        private GirlRepository girlRepository;
    
        /*
        查询所有的女生列表
         */
        @GetMapping(value = "/girls")
        public List<Girl> girlList(){
    
            List<Girl> girlList = girlRepository.findAll();
    
            return  girlList;
        }
        /*
        添加一个女生
         */
        @PostMapping(value = "/girls")
        public Girl girlAdd(@RequestParam("cupSize") String cupSize,@RequestParam("age") Integer age){
            Girl girl = new Girl();
            girl.setAge(age);
            girl.setCupSize(cupSize);
            return girlRepository.save(girl);
        }
    
        /**
         * 查询一个女生
         * @param id
         * @return
         */
        @GetMapping(value = "/girls/{id}")
        public Girl girlFindOne(@PathVariable("id") Integer id){
            return girlRepository.findOne(id);
        }
    
        /**
         * 更新女生信息
         * @param id
         * @param cupSize
         * @param age
         * @return
         */
        @PutMapping("/girls/{id}")
        public Girl girlUpdate(@PathVariable("id") Integer id, @RequestParam("cupSize") String cupSize
                , @RequestParam("age") Integer age){
            Girl girl = new Girl();
            girl.setId(id);
            girl.setCupSize(cupSize);
            girl.setAge(age);
            return girlRepository.save(girl);
        }
    
        /**
         * 删除女生信息
         * @param id
         */
        @DeleteMapping(value = "/girls/{id}")
        public void girlDelete(@PathVariable("id") Integer id){
            girlRepository.delete(id);
        }
    
        //通过年龄查询女生列表
        @GetMapping("/girls/age/{age}")
        public List<Girl>girlListByAge(@PathVariable("age") Integer age){
            return girlRepository.findByAge(age);
        }
    
    }
    

    Note:注入时注意idea的spring注解管理是否为warning

    save在有id时候为更新,无主键id时候为添加

    事务管理

      @Transactional
        public void  insertTwo(){
            Girl girlA = new Girl();
            girlA.setCupSize("B");
            girlA.setAge(18);
            girlRepository.save(girlA);
    
            Girl girlB = new Girl();
            girlB.setCupSize("Cccc");
            girlB.setAge(19);
            girlRepository.save(girlB);
        }
    

    在方法上面添加一个transational注解表示启动事务管理

    spring boot进阶之web进阶

    表单验证

    Controller方法中使用对象接收前台数据,在对象对应的类中需要验证的属性上添加比如:@Min 注解

    @Min(value = 18, message = "未成年人止步")
    private Integer age;
    

    这里value表示年龄最小值应为18,小于18的验证不通过,message为验证不通过时提示的信息

    Controller方法中形参前面添加@Valid注解,使用BindingResult接收提示信息

    @PostMapping("/boys")
    public Boy addBoy(@Valid Boy boy, BindingResult bindingResult) {
        // 如果有错误信息,即验证不通过时
        if (bindingResult.hasErrors()) {
            // 后台输出错误提示信息
            System.out.println(bindingResult.getFieldError().getDefaultMessage());
            // 返回null到前台
            return null;
        }
        return boyRepository.save(boy);
    }
    

    使用AOP处理请求

    概念

    AOP(面向切面编程)是一种编程范式,与语言无关,是一种程序设计思想

    OOP(面向对象编程) POP(面向过程编程)

    面向过程强调流程和规划,面向对象将需求功能垂直地划分为不同的,并且相对独立的,会将其封装成不同的类,让它们有自己的行为。

    AOP的关键思想是将通用逻辑从业务逻辑中分离出来

    运用

    在maven的pom.xml中添加aop依赖

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

    第一种方法:

    使用sop在控制台输出记录的日志信息

    @Aspect
    @Component
    public class BoyAspect {
        // 公用空方法,使用注解配置切入点,提高重用性
        @Pointcut("execution(public * com.lfy.BoyController.*(..))")
        public void log() {}
    
    
        // 前置增强,也可以直接在里面写execution
        @Before("log()")
        public void doBefore() {
            // 使用sop在控制台输出记录的日志信息
            System.out.println("doBefore");
        }
    
        // 最终增强
        @After("log()")
        public void doAfter() {
            System.out.println("doAfter");
        }
    }
    

    第二种方法:

    使用LoggerFactory的getLogger方法获取Logger对象,调用其info方法在控制台输出记录的日志信息

    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.http.HttpServletRequest;
    
    @Aspect
    @Component
    public class BoyAspect {
        private final static Logger logger = LoggerFactory.getLogger(BoyAspect.class);
    
        @Pointcut("execution(public * com.lfy.BoyController.*(..))")
        public void log() {}
    
        @Before("log()")
        public void doBefore(JoinPoint joinPoint) {、
            // 获取HttpServletRequest对象
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            // 输出相应信息
            // url
            logger.info("url={}", request.getRequestURI());
            // 请求方式
            logger.info("method={}", request.getMethod());
            // 请求的ip地址
            logger.info("ip={}", request.getRemoteAddr());
            // 请求调用的方法(调用JoinPoint的方法)
            logger.info("class.method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
            // 请求调用的方法的参数(调用JoinPoint的方法)
            logger.info("args={}", joinPoint.getArgs());
        }
    
        // 后置增强
        @AfterReturning(pointcut="log()", returning = "object")
        public void doAfterReturning(Object object) {
            // 输出响应信息
            logger.info("response={}", object);
        }
    
        @After("log()")
        public void doAfter() {
            logger.info("doAfter");
        }
    } 
    

    统一异常处理

    传给前台的数据格式的统一

    自定义Result类,因为返回的data数据的类型未知,故使用泛型

    public class Result<T> {
        private Integer code;
        private String message;
        private T data;
        // ...
    }
    

    Result工具类

    public class ResultUtil {
        // 成功并返回data数据
        public static Result success(Object object) {
            Result result = new Result();
            result.setCode(0);
            result.setMessage("成功");
            result.setData(object);
            return result;
        }
        // 成功不返回data数据
        public static Result success() {
            return success(null);
        }
    
        // 失败
        public static Result error(Integer code, String message) {
            Result result = new Result();
            result.setCode(code);
            result.setMessage(message);
            return result;
        }
    }
    

    统一异常处理示例

    枚举类的使用,没有set方法,因为枚举类型通过构造方法赋值

    public enum ResultEnums {
        UNKNOWN_ERROR(-1, "未知错误"),
        SUCCESS(0, "成功"),
        PRIMARY_SCHOOL(101, "小学"),
        MIDDLE_SCHOOL(102, "中学");
    
        private Integer code;
        private String message;
    
        ResultEnums(Integer code, String message) {
            this.code = code;
            this.message = message;
        }
    
        public Integer getCode() {
            return code;
        }
        public String getMessage() {
            return message;
        }
    }
    

    自定义异常,这里继承RuntimeException而不继承Exception是因为spring框架针对RuntimeException才会回滚

    public class BoyException extends RuntimeException {
        private Integer code;
    
        public Integer getCode() {
            return code;
        }
    
        public void setCode(Integer code) {
            this.code = code;
        }
    
        // 直接通过枚举类获取信息
        public BoyException(ResultEnums resultEnums) {
            super(resultEnums.getMessage());
            this.code = resultEnums.getCode();
        }
    }
    

    异常处理类

    通过@ControllerAdvice注解可以将对于控制器的全局配置放在同一个位置。

    注解了@ControllerAdvice的类的方法可以使用@ExceptionHandler等等注解到方法上。

    @ControllerAdvice注解将作用在所有注解了@RequestMapping的控制器的方法上。

    @ExceptionHandler:用于全局处理控制器里的异常。

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @ControllerAdvice
    public class ExceptionHandle {
        private static final Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
    
        @ExceptionHandler(value=Exception.class)
        @ResponseBody
        public Result handle(Exception e) {
            if (e instanceof BoyException) {
                BoyException boyException = (BoyException) e;
                return ResultUtil.error(boyException.getCode(), boyException.getMessage());
            }
            logger.info("系统异常={}", e);
            return ResultUtil.error(-1, "未知错误");
        }
    }
    

    service使用自定义异常和枚举类

    public void getAge(Integer id) throws Exception {
            Boy boy = boyRepository.findOne(id);
            Integer age = boy.getAge();
            if (age <= 10) {
                throw new BoyException(ResultEnums.PRIMARY_SCHOOL);
            } else if (age <= 16 ) {
                throw new BoyException(ResultEnums.MIDDLE_SCHOOL);
            }
        }
    

    controller,throws Exception使得处理异常返回的结果返回给前台

    @GetMapping(value="/boys/getAge/{id}")
    public void getAge(@PathVariable("id") Integer id) throws Exception {
        boyService.getAge(id);
    }
    

    单元测试

    测试service

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class BoyServiceTest {
        @Autowired
        private BoyService boyService;
        
        @Test
        public void findAllBoy() throws Exception {
            List<Boy> allBoy = boyService.findAllBoy();
            // 此处使用断言进行测试,前者是预期结果,后者是测试结果
            Assert.assertEquals(new Integer(7), allBoy.get(0).getAge());
        }
    }
    

    测试结果与预期结果不一致,控制台提示:1 test failed

    java.lang.AssertionError:

    Expected :8

    Actual :7

    一致,提示:1 test passed

    测试API

    添加@AutoConfigureMockMvc注解,使用MockMvc对象进行测试

    @RunWith(SpringRunner.class)
    @SpringBootTest
    @AutoConfigureMockMvc
    public class BoyControllerTest {
        @Autowired
        private MockMvc mvc;
    
        @Test
        public void findAllBoy() throws Exception {
            // 测试访问路径
            mvc.perform(MockMvcRequestBuilders.get("/boys"))
                    // 测试响应码是否是200(成功)
                    .andExpect(MockMvcResultMatchers.status().isOk())
                    // 测试响应的内容
                    .andExpect(MockMvcResultMatchers.content().string("123"));
        }
    }
    

    相关文章

      网友评论

          本文标题:spring boot学习笔记

          本文链接:https://www.haomeiwen.com/subject/owoxlxtx.html