视频教程链接:https://www.bilibili.com/video/BV1nV4y1s7ZN/
打开Settings页面,在左边的菜单栏依次找到Build,Execution,Dep!oyment-→Compile,勾选Build project automatically
按Ctr|+ Shift+ Alt+ /快捷键调出Maintenance页面,单击Registry,勾选compiler.automake.allow.when.app.running复选框。
做完这两步配置之后,若开发者再次在IntelliJ IDEA中修改代码,则项目会自动重启。
SpringBoot将传统Web开发的mvc、json、 tomcat等框架整合, 提供了spring-boot-starter-web组件,简化了Web应用配置。
创建SpringBoot项目勾选Spring Web选项后,会自动将spring-boot-starter-web组件加入到项目中。
spring-boot-starter-web启动器主要包括web、webmvc、 json、 tomcat等基础依赖组件,作用是提供Web开发场景所需的所有底层依赖。
webmvc为Web开发的基础框架,json为JSON数据解析组件,tomcat为自带 的容器依赖。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
Spring Boot提供了@Controller和@RestController两种注解来标识此类负责接收和处理HTTP请求。
如果请求的是页面和数据,使用@Controller注解即可;如果只是请求数据,则可以使用@RestController注解。
示例中返回了hello页面和name的数据,在前端页面中可以通过${name}参数获取后台返回的数据并显示。
@Controller通常与Thymeleaf模板弓|擎结合使用。
@Controller
public cLass HeLloControlLer {
@RequestMapping("/helLo")
public String index(ModeLMap map){
map.addAttribute( attributeName: "name" , attributeValue: "zhangsan");
return "hello";
}
}
默认情况下,@RestController注解会将返回的对象数据转换为JSON格式。
@RestController
pubLic cLass HelLoControLler {
@RequestMapping("/user")
public User getUser(){
User user = new User( );
user.setUsername("zhangsan");
user.setPassword("123");
return user;
}
}
@RequestMapping注解主要负责URL的路由映射。它可以添加在Controller类或者具体的方法上。
如果添加在Controller类上,则这个Controller中的所有 路由映射都将会加上此映射规则,如果添加在方法上,则只对当前方法生效。
@RequestMapping注解包含很多属性参数来定义HTTP的请求映射规则。常用的属性参数如下:
value:请求URL的路径,支持URL模板、正则表达式
method:HTTP请求方法
consumes:请求的媒体类型(Content-Type) , 如application/json
produces:响应的媒体类型
params, headers:请求的参数及请求头的值
@RequestMapping的value属性用于匹配URL映射,value支持简单表达式@RequestMapping("/user")
@RequestMapping支持使用通配符匹配URL,用于统一映射某些URL规则类似的请求: @RequestMapping("/getJson/* .json"),当在浏览器中请求/getJson/a.json或者/getJson/b.json时都会匹配到后台的Json方法
@RequestMapping的通配符匹配非常简单实用,支持 "*" "?" "**" 等通配符
符号 "*" 匹配任意字符,符号 "**" 匹配任意路径,符号 "?” 匹配单个字符。
有通配符的优先级低于没有通配符的,比如/user/add.json比/user/*.json优先匹配。
有 “**" 通配符的优先级低于有 "*" 通配符的。
HTTP请求Method有GET、POST、 PUT、 DELETE等方式。HTTP支持的全部Method
@RequestMapping注解提供了method参数指定请求的Method类型,包括RequestMethod.GET、RequestMethod.POST、 RequestMethod.DELETE、RequestMethod.PUT等值,分别对应HTTP请求的Method
@RequestMapping(value = "/getData" ,method = RequestMethod.GET)
//等价于 @GetMapping("/getData")
public String getData() {
return "hello ";
}
Method匹配也可以使用@GetMapping、@PostMapping等注解代替。
@RequestParam将请求参数绑定到控制器的方法参数上,接收的参数来自HTTP请求体或请求urlI的QueryString,当请求的参数名称与Controller的业务方法参数名称一致时,@RequestParam可以省略
@PathVaraible:用来处理动态的URL,URL的值可以作为控制器中处理方法的参数
@RequestBody接收的参数是来自requestBody中,即请求体。一般用于处理非Content-Type: application/x-www-form-urlencoded编码格式的数据,比如: application/json、 application/xm|等类型的数据
@RestController
public class HelloController {
// http://localhost:8080/hello?name=zhangsan&password=123456
@GetMapping("/hello")
public String Hello(String name, String password) {
System.out.println(name + "||" + password);
return "姓名:" + name + "密码:" + password;
}
}
// http://localhost:8080/hello1
@RequestMapping(value = "/hello1", method = RequestMethod.POST)
public String Hello1(User user) {
System.out.println(user);
return "姓名:" + user.getName() + "密码:" + user.getPassword();
}
// http://localhost:8080/hello2
@RequestMapping(value = "/hello2", method = RequestMethod.POST)
public String Hello2(@RequestBody User user) {
System.out.println(user);
return "姓名:" + user.getName() + "密码:" + user.getPassword();
}
@RequestBody接收的参数是来自requestBody中,即请求体。一般用于处理非Content-Type: application/x-www-form-urlencoded编码格式的数据,比如: application/json、 application/xm|等类型的数据
使用IDEA创建Spring Boot项目,会默认创建出classpath:/static/目录, 静态资源一般放在这个目录下即可。
如果默认的静态资源过滤策略不能满足开发需求,也可以自定义静态资源过滤策略。
在application.properties中直接定义过滤规则和静态资源位置:
spring.mvc.static-path-pattern=/static/**
spring.web.resources.static-locations=classpath:/static/
过滤规则为/static/**,静态资源位置为classpath:/static/
表单的enctype属性规定在发送到服务器之前应该如何对表单数据进行编码。
当表单的enctype=" application/x-www-form-urlencoded" (默认)时,form表单中的数据格式为: key=value&key=value
当表单的enctype= " multipart/form-data"时,其传输数据形式如下:
Spring Boot工程嵌入的tomcat限制了请求的文件大小,每个文件的配置最大为1Mb,单次请求的文件的总数不能大于10Mb.
要更改这个默认值需要在配置文件(如application.properties) 中加入两个配置
#每个文件的配置最大为10Mb
spring.servlet.multipart.max-file-size=10MB
#单次请求的文件的总数不能大于10Mb
spring.servlet.multipart.max-request-size=10MB
当表单的enctype=”multipart/form-data"时,可以使用MultipartFile获取上传的文件数据,再通过transferTo方法将其写入到磁盘中
@RestController
public class FileUploadController {
@PostMapping("upload")
public String upload(String nickname, MultipartFile photo, HttpServletRequest request) throws IOException {
System.out.println(nickname);
// 获取图片原始名称
System.out.println(photo.getOriginalFilename());
// 取文件类型
System.out.println(photo.getContentType());
// 上传到达路径目录
String path = request.getServletContext().getRealPath("/upload/");
System.out.println(path);
// 磁盘写入文件
SaveFile(photo, path);
return "上传成功";
}
public void SaveFile(MultipartFile photo, String path) throws IOException {
// 判断目录是否存在,不存在则创建
File dir = new File(path);
if (!dir.exists()) {
dir.mkdir();
}
// 磁盘写入文件
File file = new File(path + photo.getOriginalFilename());
photo.transferTo(file);
}
}
拦截器在Web系统中非常常见,对于某些全局统一的操作, 我们可以把它提取到拦截器中实现。总结起来,拦截器大致有以下几种使用场景:
权限检查:如登录检测,进入处理程序检测是否登录,如果没有,则直接返回登录页面。
性能监控:有时系统在某段时间莫名其妙很慢,可以通过拦截器在进入处理程序之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间
通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有提取Locale、Theme信息等,只要是多个处理程序都需要的,即可使用拦截器实现。
Spring Boot定义了HandlerInterceptor接口来实现自定义拦截器的功能
HandlerInterceptor接口定义了preHandle、postHandle、 afterCompletion三种方法,通过重写这三种方法实现请求前、请求后等操作
pub1ic class LoginInterceptor extends HandlerInterceptor {
/**
*在请求处理之前进行调用(Control1er 方法调用之前)
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("LoginInterceptor");
//中间写逻辑代码,比如判断是否登录成功,失败则返回false
return true;
}
}
addPathPatterns方法定义拦截的地址
excludePathPatterns定义排除某些地址不被拦截
添加的一个拦截器没有addPathPattern任何一个ur|则默认拦截所有请求
如果没有excludePathPatterns任何一个请求,则默认不放过任何一个请求。
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/user/**");
}
}
RESTful是目前流行的互联网软件服务架构设计风格。
REST (Representational State Transfer,表述性状态转移)一词是由RoyThomas Fielding在2000年的博士论文中提出的,它定义了互联网软件服务的架构原则,如果- -个架构符合REST原则,则称之为RESTful架构。
REST并不是一-个标准,它更像一-组客户端和服务端交互时的架构理念和设计原则,基于这种架构理念和设计原则的Web API更加简洁,更有层次。
每-个URI代表一种资源
客户端使用GET、POST、 PUT、DELETE四种表示操作方式的动词对服务端资源进行操作: GET用于获取资源,POST用于新建资源(也可以用于更新资源)PUT用于更新资源,DELETE用于删除资源。
通过操作资源的表现形式来实现服务端请求操作。
资源的表现形式是JSON或者HTML。
客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都包含必需的信息。
符合RESTful规范的Web API需要具备如下两个关键特性:
安全性:安全的方法被期望不会产生任何副作用,当我们使用GET操作获取资源时,不会引起资源本身的改变,也不会引|起服务器状态的改变。
幂等性:幂等的方法保证了重复进行一个请求和一次请求的效果相同(并不是指响应总是相同的,而是指服务器上资源的状态从第一次请求后就不再改变了),在数学上幂等性是指N次变换和一次变换相同。
HTTP提供了POST、GET、 PUT、DELETE等操作类型对某个Web资源进行Create、Read、 Update和Delete操作。
一个HTTP请求除了利用URI标志目标资源之外,还需要通过HTTP Method指定针对该资源的操作类型,一-些常见的HTTP方法及其在RESTful风格下的使用:
HTTP状态码就是服务向用户返回的状态码和提示信息,客户端的每一次请求,服务都必须给出回应,回应包括HTTP状态码和数据两部分。
HTTP定义了40个标准状态码,可用于传达客户端请求的结果。状态码分为以下5个类别:
1xx:信息,通信传输协议级信息
2xx:成功,表示客户端的请求已成功接受
3xx:重定向,表示客户端必须执行一些其他操作才 能完成其请求
4xx:客户端错误,此类错误状态码指向客户端
5xx:服务器错误,服务器负责这写错误状态码
RESTful API中使用HTTP状态码来表示请求执行结果的状态,适用于REST API设计的代码以及对应的HTTP方法。
Spring Boot提供的spring-boot-starter-web组件完全支持开发RESTful API,提供了与REST操作方式(GET、 POST、 PUT、 DELETE)对应的注解。
@GetMapping:处理GET请求,获取资源。
@PostMapping:处理POST请求,新增资源。
@PutMapping:处理PUT请求,更新资源。
@DeleteMapping:处理DELETE请求,删除资源。
@PatchMapping:处理PATCH请求,用于部分更新资源。
在RESTful架构中,每个网址代表- -种资源, 所以URI中建议不要包含动词,只包含名词即可,而且所用的名词往往与数据库的表格名对应。
@RestController
public class UserController {
@GetMapping("/user/{id}")
public String getUserById(@PathVariable int id) {
System.out.println("ID: " + id);
return "根据ID获取用户";
}
@PostMapping("/user")
public String save(User user) {
return "添加用户";
}
@PutMapping("/user")
public String update(User user) {
return "更新用户";
}
@DeleteMapping("/user/{id}")
public String deleteById(@PathVariable int id) {
System.out.println("ID: " + id);
return "根据ID删除用户";
}
}
Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务,是非常流行的API表达工具。
Swagger能够自动生成完善的RESTful API文档,同时并根据后台代码的修改同步更新,同时提供完整的测试页面来调试API。
在Spring Boot项目中集成Swagger同样非常简单,只需在项目中引入springfox- swagger2和springfox- swagger-ui依赖即可。
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.9.2version>
dependency>
@Configuration //告诉Spring容器,这个类是一个配置类
@EnableSwagger2 // 启用Swagger2功能
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
// com.switchvov.swagger包下所有API都交给Swagger2管理
.apis(RequestHandlerSelectors.basePackage("com.switchvov.swagger"))
.paths(PathSelectors.any())
.build();
}
/**
* API文档页面显示信息
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Swagger测试项目 RESTful APIs") //标题
.description("study Swagger2 Demo") //描述
.version("1.0")
.build();
}
}
Swagger UI
ORM (Object Relational Mapping,对象关系映射)是为了解决面向对象与关系数据库存在的互不匹配现象的一种技术。
ORM通过使用描述对象和数据库之间映射的元数据将程序中的对象自动持久化到关系数据库中。
ORM框架的本质是简化编程中操作数据库的编码。
官网:
MyBatis-Plus (baomidou.com)
MyBatis是一款优秀的数据持久层ORM框架, 被广泛地应用于应用系统。
MyBatis能够非常灵活地实现动态SQL,可以使用XML或注解来配置和映射原生信息,能够轻松地将Java的POJO (Plain Ordinary Java Object,普通的Java对象)与数据库中的表和字段进行映射关联。
MyBatis- Plus是一个MyBatis的增强工具,在MyBatis的基础上做了增强,简化了开发。
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.4.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.20version>
dependency>
application.properties 配置数据库相关信息
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot??AllowPublicKeyRetrieval=True
spring.datasource.username=root
spring.datasource.password=root
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
创建mapper包,添加@MapperScan注解
在Spring Boot启动类中添加@MapperScan注解,扫描Mapper文件夹
@SpringBootApplication
@MapperScan("com.example.mpdemo.mapper")
public class MpdemoApplication {
public static void main(String[] args) {
SpringApplication.run(MpdemoApplication.class, args);
}
}
Mybatis CRUD注解
创建与数据库表对应的User实体类
public class User {
private int id;
private String username;
private String password;
private String birthday;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", birthday='" + birthday + '\'' +
'}';
}
}
创建User实体类的数据库接口类UserMapper
@Mapper
public interface UserMapper {
// 查询所有用户
@Select("select * from user")
public List<User> find();
// 新增用户
@Insert("insert into user values (#{id},#{username},#{password},#{birthday})")
public int insert(User user);
}
创建UserController
@RestController
public class UserController {
// 自动注入Mapper
@Autowired
// 使用UserMapper接口
public UserMapper userMapper;
// 查询所有用户
@GetMapping("/user")
public List query() {
List<User> userList = userMapper.find();
System.out.println(userList);
// return "查询用户";
return userList; //返回JSON格式的数据
}
// 新增用户
@PostMapping("/user")
public String save(User user) {
int insertUser = userMapper.insert(user);
if (insertUser > 0) {
return "插入成功";
} else {
return "插入失败";
}
}
/*
* BaseMapper<实体类>
*mybatisplus会根据实体类找到数据库表,然后帮你操作增删改查
* 前提是实体类名字要与数据库表的名字一致
* */
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
@RestController
public class UserController {
// 自动注入Mapper
@Autowired
// 使用UserMapper接口
public UserMapper userMapper;
// 查询所有用户
@GetMapping("/user")
public List query() {
List<User> userList = userMapper.selectList(null);
System.out.println(userList);
// return "查询用户";
return userList; //返回JSON格式的数据
}
// 新增用户
@PostMapping("/user")
public String save(User user) {
int insertUser = userMapper.insert(user);
if (insertUser > 0) {
return "插入成功";
} else {
return "插入失败";
}
}
注解解析:
注解 | MyBatis-Plus (baomidou.com)
@TableName:表名注解,标识实体类对应的表
@TableId:主键注解
TableFiled:字段注解(非主键)
@Version:乐观锁注解、标记 @Version 在字段上
@EnumValue:普通枚举类注解(注解在枚举字段上)
@TableLogic:表字段逻辑处理注解(逻辑删除)
实现复杂关系映射,可以使用@Results注解,@Result注解, @One注解,@Many注解组合完成复杂关系的配置。
创建数据库表order的实体类
public class Order {
@TableId(type = IdType.AUTO)
private int id;
private String ordertime;
private String total;
private int uid;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getOrdertime() {
return ordertime;
}
public void setOrdertime(String ordertime) {
this.ordertime = ordertime;
}
public String getTotal() {
return total;
}
public void setTotal(String total) {
this.total = total;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
@Override
public String toString() {
return "Order{" +
"id=" + id +
", ordertime='" + ordertime + '\'' +
", total='" + total + '\'' +
", uid=" + uid +
'}';
}
}
在user实体类中添加订单信息的映射
// 描述用户的所有订单
// 查询所有的字段中是否存在orders,不存在则自动进行数据库的映射
@TableField(exist = false)
private List<Order> orders;
public List<Order> getOrders() {
return orders;
}
public void setOrders(List<Order> orders) {
this.orders = orders;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", birthday='" + birthday + '\'' +
", orders=" + orders +
'}';
}
创建OrderMapper数据库接口类
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
// 根据订单ID查询订单信息
@Select("select * from t_order where uid = #{uid}")
List<Order> selectByUId(int uid);
// 查询所有的订单信息以及对应的用户信息
@Select("select * from t_order")
@Results({
@Result(column = "id", property = "id"),
@Result(column = "ordertime", property = "ordertime"),
@Result(column = "total", property = "total"),
@Result(column = "uid", property = "user", javaType = User.class,
one = @One(select = "com.example.mpdemo.mapper.UserMapper.selectById")
)
})
List<Order> selectAllOrderAndUser();
}
UserController添加查询所有用户信息的接口
// 查询所有的用户数据以及订单数据
@GetMapping("/user/findAll")
public List<User> find() {
return userMapper.selectAllUserAndOrders();
}
测试查询结果
在Order实体类中添加获取用户信息的字段及其get、set和toString方法
@TableField(exist = false)
private User user;
在UserMapper中添加查询所有订单订单以及对应的用户信息的方法
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 根据用户id查询用户信息
@Select("select * from user where id = #{id}")
User selectAllByIdUser(int id);
// 查询所有用户及其所有的订单
@Select("select * from user")
@Results({
@Result(column = "id", property = "id"),
@Result(column = "username", property = "username"),
@Result(column = "password", property = "password"),
@Result(column = "id", property = "orders", javaType = List.class,
many = @Many(select = "com.example.mpdemo.mapper.OrderMapper.selectByUId")
)
})
List<User> selectAllUserAndOrders();
}
创建OrderController订单控制类
@RestController
public class OrderController {
@Autowired
private OrderMapper orderMapper;
@GetMapping("/order/findAll")
public List orderFindAll() {
List ordersList = orderMapper.selectAllOrderAndUser();
return ordersList;
}
}
测试查询结果
方式一:可以通过查询语句进行拼接查询
方式二:使用MyBatis-Plus提供的条件查询方法(AbstractWrapper)
条件构造器 | MyBatis-Plus (baomidou.com)
// 条件查询
@GetMapping("/user/find")
public List<User> findByCond() {
/*
* AbstractWrapper
* QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类
* 用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件
* */
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", "zhangsan");
// selectList:MyBatis-Plus提供的条件查询方法
return userMapper.selectList(queryWrapper);
}
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// DbType: 使用的数据库类型
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
}
// 分页查询
@GetMapping("/user/findByPage")
public IPage findByPage() {
// 设置起始值及每页条数
Page<User> page = new Page<>(0, 2);
// selectPage: MyBatis-Plus提供的分页查询方法
// IPage:用于描述结果集
IPage iPage = userMapper.selectPage(page, null);
return iPage;
}