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;
}
}