spring boot

作者: inke | 来源:发表于2017-04-26 15:58 被阅读66次

    spring boot

    配置文件:

    格式一:

    application.properties

    例如:添加全局访问路径和修改 Tomcat 的端口号

    server.context-path=/demo
    server.port=8081
    

    格式二:

    • 系统属性 application.yml

      例如:添加全局访问路径 和 修改 Tomcat 的端口号

      server:
        context-path: /demo
        port: 8081
      
    • 自定义属性:application.yml

      age: 18 # 自定义属性
      name: inke # 自定义属性
      content: "name:${name},age:${age}" #配置引用配置
      

      在代码中引用 HelloController.java

      @Value("${age}")
      private Integer age;//@value可以获取application.yml配置的值
      
      @RestController
      public class HelloController {
      }    
      
    • 类和属性关联

      application.yml

      person:
        age: 18 # 自定义属性
        name: inke # 自定义属性
      

      Person.java

      @Component
      @ConfigurationProperties(prefix = "person")
      public class Person {
          private String name;
          private Integer age;
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public Integer getAge() {
              return age;
          }
      
          public void setAge(Integer age) {
              this.age = age;
          }
      }
      

      在代码中引用 HelloController.java

      @RestController
      public class HelloController {
      
      //    @Value("${age}")
      //    private Integer age;
      //
      //    @Value("${content}")
      //    private String content;
      
          @Autowired
          private Person person;
      
          @RequestMapping(value = "/hello")
          public String sayHello() {
              return "hello world name:" + person.getName() + " , age:" + person.getAge();
          }
      }
      

    多个配置文件切换

    application.yml 通过 active 指定的属性的环境:dev 还是 prod

    spring:
      profiles:
        active: prod
    

    application-dev.yml

    person:
      age: 18 # 自定义属性
      name: dev001 # 自定义属性
    

    application-prod.yml

    person:
      age: 18 # 自定义属性
      name: prod001 # 自定义属性
    

    启动的时候,会根据 active 指定的环境属性文件进行加载。


    Controller

    示例:

    HelloController

    package com.example;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloController {
    
        @Value("${age}")
        private Integer age;//@value可以获取application.yml配置的值
    
        @RequestMapping(value = "/hello")
        public String sayHello() {
            return "hello world age:" + age;
        }
    }
    

    application.yml

    age: 18
    

    常用注解

    @RestController = @Controller + @ResponseBody
    @Controller需要返回 template 模版,类似于 Django 的模板。
    建议使用@RestController


    映射多个路径

    • 单个映射:@RequestMapping(value = "/hello")
    @RequestMapping(value = "/hello")
    public String sayHello() {
       return "hello world name:" + person.getName() + " , age:" + person.getAge();
    }
    
    • 多个映射:@RequestMapping(value = {"hello", "hi"})
    @RequestMapping(value = {"hello", "hi"})
    public String sayHello() {
       return "hello world name:" + person.getName() + " , age:" + person.getAge();
    }
    
    • 整个 controller 增加映射,在类上增加:@RequestMapping(value = "/demo")
    @RestController
    @RequestMapping(value = "/demo")
    public class HelloController {
    
        @Autowired
        private Person person;
    
        @RequestMapping(value = {"hello", "hi"})
        public String sayHello() {
            return "hello world name:" + person.getName() + " , age:" + person.getAge();
        }
    }
    

    访问方式:

    • method = RequestMethod.GET
    • method = RequestMethod.POST
    • ...
    • 简便方式:
      • @GetMapping(value = "hello")
      • @PostMapping(value = "hello")
    @RestController
    @RequestMapping(value = "/demo")
    public class HelloController {
    
        @Autowired
        private Person person;
    
        @RequestMapping(value = {"hello", "hi"}, method = RequestMethod.GET)
        //@GetMapping(value = "hello")
        public String sayHello() {
            return "hello world name:" + person.getName() + " , age:" + person.getAge();
        }
    }
    

    注意:什么都不写,默认是 get 和 post 都可以访问,但是不建议这样做,需要明确指定访问方式。


    获取访问参数

    • 获取 GETURL 的参数和 POST 的 请求 body 参数

      • 字段field映射
      @RequestMapping(value = "hello", method = RequestMethod.GET)
      public String sayHello(@RequestParam(value = "id", required = false, defaultValue = "0") Integer id) {
         return "id:" + id;
      }
      
      • 实体 model 映射
      @PostMapping(value = "/addPerson")
      public Person addPerson(Person person) {
         return personRespository.save(person);
      }
      
    • 获取 restfully 参数
    @RequestMapping(value = "hello/{id}", method = RequestMethod.GET)
    public String sayHello(@PathVariable("id") Integer id) {
       return "id:" + id;
    }
    

    数据库

    • 准备工作,加入数据库的配置和依赖

      pom.xml

      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
      </dependency>
      
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
      </dependency>
      

      application.yml

      spring:
        profiles:
          active: prod
        datasource:
          driver-class-name: com.mysql.jdbc.Driver
          url: jdbc:mysql://localhost:3306/springboot
          username: root
          password: root
        jpa:
          hibernate:
            ddl-auto: create
          show-sql: true
      

      Person.java

      @Entity
      public class Person {
      
          @Id
          @GeneratedValue
          private Integer id;
          private String name;
          private Integer age;
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public Integer getAge() {
              return age;
          }
      
          public void setAge(Integer age) {
              this.age = age;
          }
      }
      

      创建接口继承JpaRepository,泛型使用的是

      public interface PersonRespository extends JpaRepository<Person, Integer> {
      }
      
    • 单表简单查询

      HelloController.java

      @RestController
      public class HelloController {
      
          @Autowired
          private PersonRespository personRespository;
      
          @PostMapping(value = "/addPerson")
          public Person addPerson(@RequestParam(value = "name") String name, @RequestParam(value = "age") Integer age) {
              Person person = new Person();
              person.setName(name);
              person.setAge(age);
              return personRespository.save(person);
          }
          
              @DeleteMapping(value = "/delPerson/{id}")
          public void delPerson(@PathVariable(value = "id") Integer id) {
              personRespository.delete(id);
          }
      
          @PutMapping(value = "/updatePerson")
          public Person updatePerson(@RequestParam(value = "id") Integer id, @RequestParam(value = "name") String name, @RequestParam(value = "age") Integer age) {
              Person person = new Person();
              person.setId(id);
              person.setName(name);
              person.setAge(age);
              return personRespository.save(person);
          }
      
          @GetMapping(value = "/findPerson/{id}")
          public Person findPerson(@PathVariable(value = "id") Integer id) {
              return personRespository.findOne(id);
          }
      
          @GetMapping(value = "/findPersons")
          public List<Person> findPerson() {
              return personRespository.findAll();
          }
      }
      
    • 单表根据年龄查询

      PersonRespository.java

      增加一个根据年龄查询的抽象方法

      public interface PersonRespository extends JpaRepository<Person, Integer> {
          Person findByAge(Integer age);
      }
      

      HelloController.java

      @RestController
      public class HelloController {
      
          @Autowired
          private PersonRespository personRespository;
      
          @GetMapping(value = "/findPersonByAge/{age}")
          public Person findPersonByAge(@PathVariable(value = "age") Integer age) {
              return personRespository.findByAge(age);
          }
      }
      

    事务管理

    在方法名称上增加@Transactional,该方法就有事务管理了。

    @Service
    public class PersonService {
    
        @Autowired
        private PersonRespository personRespository;
    
        @Transactional
        public void insertTwo() {
            Person person = new Person();
            person.setName("jack");
            person.setAge(40);
            personRespository.save(person);
    
            Person person1 = new Person();
            person1.setName("rose");
            person1.setAge(30000);
            int a = 1 / 0;
            personRespository.save(person1);
    
        }
    }
    

    校验

    在 model 增加注解 @Min(value = 18,message = "不能小于18岁")

    @Entity
    public class Person {
    
        @Id
        @GeneratedValue
        private Integer id;
        private String name;
        
        @Min(value = 18,message = "不能小于18岁")
        private Integer age;
    
        。。。set、get 方法
    }
    

    在 controller 的 model 增加@Valid注解,同时可以BindingResult获取校验的信息。

    @PostMapping(value = "/addPerson")
    public Person addPerson(@Valid Person person, BindingResult bindingResult) {
       if (bindingResult.hasErrors()) {
           //输出错误信息:不能小于18岁
           System.out.print(bindingResult.getFieldError().getDefaultMessage());
       }
       return personRespository.save(person);
    }
    

    AOP

    • 创建切面方式一:

      @Aspect
      @Component
      public class HttpAspect {
      
      
          @Before("execution(public * com.example.HelloController.*(..))")
          public void logBefore() {
              System.out.print("logBefore");
          }
      
      
          @After("execution(public * com.example.HelloController.*(..))")
          public void logAfter() {
              System.out.print("logAfter");
          }
      }
      
    • 创建切面方式二:(抽取切点出来,减少重复代码)

      @Aspect
      @Component
      public class HttpAspect {
      
          @Pointcut("execution(public * com.example.HelloController.*(..))")
          public void log() {
      
          }
      
          @Before("log()")
          public void logBefore() {
              System.out.print("logBefore");
          }
      
      
          @After("log()")
          public void logAfter() {
              System.out.print("logAfter");
          }
      }
      
    @Aspect
    @Component
    public class HttpAspect {
    
        public static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
    
        @Pointcut("execution(public * com.example.HelloController.*(..))")
        public void log() {
    
        }
    
        @Before("log()")
        public void logBefore(JoinPoint joinPoint) {
            logger.info("logBefore");
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = servletRequestAttributes.getRequest();
            logger.info("url={}", request.getRequestURL());
            logger.info("method={}", request.getMethod());
            logger.info("ip={}", request.getRemoteAddr());
            logger.info("class.method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
            logger.info("args={}", joinPoint.getArgs());
        }
    
    
        @After("log()")
        public void logAfter() {
            logger.info("logAfter");
        }
    
        @AfterReturning(returning = "object", pointcut = "log()")
        public void logAfterReturning(Object object) {
            logger.info("response={}", object.toString());
        }
    }
    
    
    输出日志:
    
    logBefore
    url=http://localhost:8080/updatePerson
    method=PUT
    ip=0:0:0:0:0:0:0:1
    class.method=com.example.HelloController.updatePerson
    args=10
    m person person0_ where person0_.id=?
    logAfter
    response=com.example.Person@34b98c82
    

    日志

    public static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
    
        @Pointcut("execution(public * com.example.HelloController.*(..))")
        public void log() {
    
        }
    
        @Before("log()")
        public void logBefore() {
            logger.info("logBefore");
        }
    
    
        @After("log()")
        public void logAfter() {
            logger.info("logAfter");
        }
    

    异常处理

    定义常量枚举:ResultEnum.java

    public enum ResultEnum {
    
        UNKNOW(-1, "未知错误"),
        OKKK(100, "小于18岁"),
        NOOO(101, "大于50岁"),;
    
        private Integer code;
        private String msg;
    
        ResultEnum(Integer code, String mag) {
            this.code = code;
            this.msg = mag;
        }
    
        public Integer getCode() {
            return code;
        }
    
        public void setCode(Integer code) {
            this.code = code;
        }
    
        public String getMag() {
            return msg;
        }
    
        public void setMag(String mag) {
            this.msg = mag;
        }
    }
    

    自定义异常类:PersonException.java

    public class PersonException extends Exception {
        private Integer code;
        private String msg;
    
        public Integer getCode() {
            return code;
        }
    
        public void setCode(Integer code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public PersonException(ResultEnum resultEnum) {
            this.code = resultEnum.getCode();
            this.msg = resultEnum.getMag();
        }
    }
    

    定义返回结果类:ResultInfo.java

    public class ResultInfo<T> implements Serializable {
        private int code;
        private String msg;
        private T data;
    
        public ResultInfo(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    }
    

    全局异常处理类ResultExceptionHandle.java

    @ControllerAdvice
    public class ResultExceptionHandle {
    
        @ExceptionHandler(value = Exception.class)
        @ResponseBody
        public ResultInfo handleException(Exception e) {
            if (e instanceof PersonException) {
                PersonException personException = (PersonException) e;
                return new ResultInfo(personException.getCode(), personException.getMsg());
            }
            return new ResultInfo(-1, "未知错误");
        }
    }
    

    Controller 正常调用,全局 Exception 会自动拦截处理 HelloController.java

    @RestController
    public class HelloController {
        @Autowired
        private PersonRespository personRespository;
    
        @PostMapping(value = "/addPerson")
        public Person addPerson(@Valid Person person, BindingResult bindingResult) throws Exception {
            if (bindingResult.hasErrors()) {
                //输出错误信息
                System.out.print(bindingResult.getFieldError().getDefaultMessage());
            }
            return personService.save(person);
        }
    }
    

    单元测试

    需要模拟 http 请求进行单元测试,类上要添加注解(@RunWith(SpringRunner.class)@SpringBootTest@AutoConfigureMockMvc),方法上也要添加注解(@Test),使用MockMvc进行请求模拟。

    @RunWith(SpringRunner.class)
    @SpringBootTest
    @AutoConfigureMockMvc
    public class PersonControllerTest {
    
        @Autowired
        private MockMvc mockMvc;
    
        @Test
        public void findPerson() throws Exception {
            mockMvc.perform(MockMvcRequestBuilders.get("/findPersons")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().string("hello"));
        }
    }
    

    打包默认会运行所有单元测试,可以通过参数跳过单元测试。

    相关文章

      网友评论

        本文标题:spring boot

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