Spring Boot入门(二)开发web应用
Web开发
Spring Boot Web 开发非常的简单,其中包括常用的 json 输出、filters、property、log 等
返回json
在控制器上添加@RestController
Spring Boot默认类中的方法都会以 json 的格式返回
@RestController
public class HelloController {
    @RequestMapping("/getUser")
    public User getUser() {
        User user = new User();
        user.setUser("张三");
        return user;
    }
}
User类
package com.example.demo.model;
import lombok.Data;
@Data
public class User {
    private String User;
}
@Data是lombok的注解用于生成get、set方法
引用如下
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
{"user":"张三"}
如果需要使用页面开发只要使用@Controller注解即可
@RestController等同于
@Controller
@ResponseBody
public class HelloController {
}
自定义Filter
我们常常在项目中会使用 filters 用于录调用日志、排除有 XSS 威胁的字符、执行权限验证等等。Spring Boot 自动添加了 OrderedCharacterEncodingFilter 和 HiddenHttpMethodFilter,并且我们可以自定义 Filter。
@Configuration注解拦截
两个步骤:
- 实现 Filter 接口,实现 Filter 方法
- 添加
@Configuration注解,将自定义Filter加入过滤链
package com.example.demo.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class MyFilter implements Filter {
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }
    @Override
    public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain filterChain)
            throws IOException, ServletException {
        // TODO Auto-generated method stub
        HttpServletRequest request = (HttpServletRequest) srequest;
        System.out.println("this is MyFilter,url :"+request.getRequestURI());
        filterChain.doFilter(srequest, sresponse);
    }
    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub
    }
}
package com.example.demo.config;
import com.example.demo.filter.MyFilter;
import org.apache.catalina.filters.RemoteIpFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebConfiguration {
    @Bean
    public RemoteIpFilter remoteIpFilter() {
        return new RemoteIpFilter();
    }
    @Bean
    public FilterRegistrationBean testFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new MyFilter());
        registration.addUrlPatterns("/*");
        registration.addInitParameter("paramName", "paramValue");
        registration.setName("MyFilter");
        registration.setOrder(1);
        return registration;
    }
}
运行后访问localhost:8080/getUser 控制台打印
this is MyFilter,url :/getUser
@WebFilter + @ServletComponentScan注解拦截
在MyFilter类中添加@WebFilter(urlPatterns = "/*", filterName = "reqResFilter")注解
package com.example.demo.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@WebFilter(urlPatterns = "/*", filterName = "reqResFilter")
public class MyFilter implements Filter {
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }
    @Override
    public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain filterChain)
            throws IOException, ServletException {
        // TODO Auto-generated method stub
        HttpServletRequest request = (HttpServletRequest) srequest;
        System.out.println("this is MyFilter,url :"+request.getRequestURI());
        filterChain.doFilter(srequest, sresponse);
    }
    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub
    }
}
在Spring Boot启动类添加@ServletComponentScan
@SpringBootApplication
@ServletComponentScan
public class DemoApplication {
	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}
运行后访问localhost:8080/getUser 控制台打印
this is MyFilter,url :/getUser
自定义配置
在 Web 开发的过程中,我经常需要自定义一些配置文件,如何使用呢
配置application.properties
在resources-> application.properties 中
config.title="配置标题"
config.description="标题描述"
自定义配置类
package com.example.demo.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Data
public class ConfigProperties {
    @Value("${config.title}")
    private String title;
    @Value("${config.description}")
    private String description;
}
重新修改下HelloWorldController文件
package com.example.demo.controller;
import com.example.demo.config.ConfigProperties;
import com.example.demo.model.User;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Data
public class HelloWorldController {
    @Autowired
    private ConfigProperties config;
    @RequestMapping("/getUser")
    public User getUser() {
        User user = new User();
        user.setUser(config.getTitle()+config.getDescription());
        return user;
    }
}
重新启动
输出
{"user":"\"配置标题\"\"标题描述\""}
配置文件乱码
- 设置 File Encodings的Transparent native-to-ascii conversion为true,具体步骤如下:依次点击
File -> Settings -> Editor -> File Encodings
将Properties Files (*.properties)下的Default encoding for properties files设置为UTF-8,将Transparent native-to-ascii conversion前的勾选上

2 .配置完成后,一定要 重新重新重新 新建一个application.properties
使用yml
删除application.properties 文件
新建application.yml文件
config:
  title: "配置标题"
  description: "标题描述"
重启
输出
{"user":"配置标题标题描述"}
Spring Boot Rest API
REST介绍
REST代表Representational State Transfer. 是一种架构风格,设计风格而不是标准,可用于设计Web服务,可以从各种客户端使用.
基于REST的基本设计,其是根据一组动词来控制的操作
- 创建操作:应使用HTTP POST
- 查询操作:应使用HTTP GET
- 更新操作:应使用HTTP PUT
- 删除操作:应使用HTTP DELETE
作为REST服务开发人员或客户端,您应该遵守上述标准。
新建HomeController
package com.example.demo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HomeController {
    @RequestMapping(method = RequestMethod.GET)
    public String Get(){
        return "get";
    }
    @RequestMapping(method = RequestMethod.POST)
    public String insert(){
        return "insert";
    }
    @RequestMapping(method = RequestMethod.PUT)
    public String update(){
        return "update";
    }
    @RequestMapping(method = RequestMethod.DELETE)
    public String delete(){
        return "delete";
    }
}
通过POSTMAN访问
也可以通过指定的注解@GetMapping、@PostMapping、@PutMapping、@DeleteMapping指定不同的请求方式与上面的方法相同
package com.example.demo.controller;
import org.springframework.web.bind.annotation.*;
@RestController
public class HomeController {
    @GetMapping("/home")
    public String Get(){
        return "get";
    }
    @PostMapping("/home")
    public String insert(){
        return "insert";
    }
    @PutMapping("/home")
    public String update(){
        return "update";
    }
    @DeleteMapping("/home")
    public String delete(){
        return "delete";
    }
}
Log
使用自带日志Slf4j
log4j2 漏洞解析 - 池的巧克力 - 博客园 (cnblogs.com)
Spring Boot 版本不要低于2.5.8
org.apache.logging.log4j  > 2.15
如果你的Spring Boot 版本低于2.5.8
使用的是父 POM,则可以设置以下属性:log4j2.version
<properties>
    <log4j2.version>2.17.0</log4j2.version>
</properties>
如果您没有父级,而是导入 BOM 表,则需要使用一个部分:
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-bom</artifactId>
            <version>2.17.0</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>
或者参考这里:Log4J2 Vulnerability and Spring Boot
package com.example.demo.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@Slf4j
@RestController
public class HomeController {
    @GetMapping("/home")
    public String Get(){
        log.info("日志记录");
        return "get";
    }
    @PostMapping("/home")
    public String insert(){
        return "insert";
    }
    @PutMapping("/home")
    public String update(){
        return "update";
    }
    @DeleteMapping("/home")
    public String delete(){
        return "delete";
    }
}
如果没有配置文件就只在控制台输出
2021-12-22 15:50:56.745  INFO 34316 --- [nio-8080-exec-1] c.e.demo.controller.HomeController       : 日志记录
默认情况下,Spring Boot 仅记录到控制台,不写入日志文件。如果要写入除控制台输出之外的日志文件,则需要设置 属性
在application.yml文件中
logging:
  file:
    name: my.log
然后在根目录查看生成的文件
查看更多信息核心特性 (spring.io)
数据库操作(MyBatis)
如果你不会使用MyBatis请查看MyBatis(一)MyBatis初识 - 青杉 - 博客园 (cnblogs.com)
引入依赖
<!--引入 mybatis-spring-boot-starter 的依赖-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.3</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.27</version>
</dependency>
配置 MyBatis
在 Spring Boot 的配置文件(application.properties/yml)中对 MyBatis 进行配置,例如指定 mapper.xml 的位置、实体类的位置、是否开启驼峰命名法等等,示例代码如下。
mybatis:
  # 指定 mapper.xml 的位置
  mapper-locations: classpath:mapper/*.xml
  #扫描实体类的位置,在此处指明扫描实体类的包,在 mapper.xml 中就可以不写实体类的全路径名
  type-aliases-package: com.example.demo.mapper
  configuration:
    #默认开启驼峰命名法,可以不用设置该属性
    map-underscore-to-camel-case: true
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/jdbc_test?useUnicode=true&characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
    driver-class-name: "com.mysql.cj.jdbc.Driver"
注意:使用 MyBatis 时,必须配置数据源信息,例如数据库 URL、数据库用户型、数据库密码和数据库驱动等。
Sql语句
CREATE DATABASE IF NOT EXISTS `jdbc_test`;
DROP TABLE IF EXISTS `blog`;
CREATE TABLE `blog` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `blog_title` varchar(20),
  `desc` varchar(300),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;
创建实体类
package com.example.demo.entity;
import lombok.Data;
@Data
public class Blog {
    private int id;
    private String blogTitle;
    private String desc;
}
创建 Mapper 接口
package com.example.demo.mapper;
import com.example.demo.entity.Blog;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface BlogMapper {
    int insert(Blog blog);
    int delete(int id);
    int update(Blog blog);
    List<Blog> getAll();
}
创建 Mapper 映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.BlogMapper">
    <resultMap id="blogMap" type="com.example.demo.entity.Blog">
        <id property="id" column="id" />
        <result property="blogTitle" column="blog_title"/>
        <result property="desc" column="desc"/>
    </resultMap>
    <select id="getAll" resultMap="blogMap">
        select * from Blog
    </select>
    <insert id="insert">
        insert into Blog(blog_title,`desc`) value (#{blogTitle},#{desc})
    </insert>
    <update id="update">
        update Blog set blog_title=#{blogTitle} where id=#{id}
    </update>
    <update id="delete">
        delete from Blog where id=#{id}
    </update>
</mapper>
当 mapper 接口较多时,我们可以在 Spring Boot 主启动类上使用 @MapperScan 注解扫描指定包下的 mapper 接口,而不再需要在每个 mapper 接口上都标注 @Mapper 注解。
创建BlogController控制器
package com.example.demo.controller;
import com.example.demo.entity.Blog;
import com.example.demo.mapper.BlogMapper;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RestController
@Data
public class BlogController {
    @Resource
    private BlogMapper blogMapper;
    @GetMapping("/blog")
    public List<Blog> GetAll(){
        return blogMapper.getAll();
    }
    @PostMapping("/blog")
    public int insert(@RequestBody Blog blog){
        return blogMapper.insert(blog);
    }
    @PutMapping("/blog")
    public int update(@RequestBody Blog blog){
        return blogMapper.update(blog);
    }
    @DeleteMapping("/blog/{id}")
    public int delete(@PathVariable int id){
        return blogMapper.delete(id);
    }
}
使用postMan测试
事务
在方法上@Transactional
如下
@PostMapping("/blog")
@ApiOperation(value = "添加博客")
@Transactional
public int insert(@RequestBody Blog blog){
    blogMapper.insert(blog);
    int i = 1/0;
    return blogMapper.insert(blog);
}
Spring Boot全局异常处理
package com.example.demo.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
@Slf4j
@ControllerAdvice
public class GlobalExceptionHander {
    @ResponseBody
    @ExceptionHandler(value =Exception.class)
    public String handleControllerException(HttpServletRequest request, Exception ex) {
        log.error("发生错误:",ex);
        return ex.getMessage();
    }
}
Swagger
springfox/springfox:使用Spring构建的API的自动JSON API文档 (github.com)
1.引入依赖
<!--引入 swagger 的依赖-->
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-boot-starter</artifactId>
   <version>3.0.0</version>
</dependency>
问题
如果出现以下错误
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
这是因为Springfox使用的路径匹配是基于AntPathMatcher的,而Spring Boot 2.6.X使用的是PathPatternMatcher。
需要添加以下配置
spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
2. 应用主类增加注解@EnableOpenApi。
@EnableOpenApi
@SpringBootApplication
public class DemoApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
3.配置一些接口例子
@Api(tags = "博客管理")
@RestController
@Data
public class BlogController {
    @Resource
    private BlogMapper blogMapper;
    @ApiOperation(value = "获取所有博客")
    @GetMapping("/blog")
    public List<Blog> GetAll(){
        return blogMapper.getAll();
    }
    @PostMapping("/blog")
    @ApiOperation(value = "添加博客")
    public int insert(@RequestBody Blog blog){
        return blogMapper.insert(blog);
    }
    @PutMapping("/blog")
    @ApiOperation(value = "修改博客")
    public int update(@RequestBody Blog blog){
        return blogMapper.update(blog);
    }
    @DeleteMapping("/blog/{id}")
    @ApiOperation(value = "删除博客")
    public int delete(@PathVariable int id){
        return blogMapper.delete(id);
    }
}
package com.example.demo.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel(description = "博客")
@Data
public class Blog {
    @ApiModelProperty("id")
    private int id;
    @ApiModelProperty("博客标题")
    private String blogTitle;
    @ApiModelProperty("描述")
    private String desc;
}
4.启动
启动应用!访问swagger页面:http://localhost:8080/swagger-ui/index.html
模型验证
引入
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
使用
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
@Data
public class UserDto {
    @Length(min = 6,max = 18,message = "password长度必须位于6到18之间")
    private String password;
    @NotEmpty(message = "请填写手机号")
    private String mobile;
}
/**
 * 类注解
 */
@RestController
@RequestMapping("test")
public class TestController {
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public UserDto Test(@Validated UserDto user){
        return u;
    }
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号