框架、Spring、SpringBoot
框架:简单来说就是写好的东西的集合;
Spring框架:管理对象的创建和使用,核心是通过容器(IOC)管理对象

缺点:使用比较繁琐

SpringBoot框架:核心是约定大于配置。内嵌了Tomcat服务器。(注解代替配置文件)

上图中直接使用Component注解就在容器中创建了类对象。
创建SpringBoot项目
首先下载好JDK和IDEA。


这里的依赖可以先不选择,后续在pom.xml文件中自行配置。

创建成功后如上图,这里我们将Maven源换成阿里源。

上图所示就是配置成功。

蓝色选中部分可以删掉。

application.properties是SpringBoot项目中的配置文件,用于配置对象相关参数,例如定义数据库的账户名、密码、项目端口号等。yml格式现在更为主流,这里我们直接修改其后缀名。
SpringBoot整合SpringMvc实现第一个api接口
要使用SpringMvc,先在pom.xml文件中添加依赖。

第三项为新添加项,刷新后即可正常使用。
为什么这个依赖没有版本号?因为当前项目的父项目的父项目使用了dependencyManagement进行管理,父pom统一管理子模块依赖版本。

使用SpringMVC的话直接使用注解即可。
@Controller和@RestController区别
Controller:返回页面(HTML、视图),如果要返回JSON,必须手动加@ResponseBody。不适用于前后端分离系统。
RestController:直接返回数据 (JSON / 字符串 / XML),自动给所有方法加上 @ResponseBody,不会返回页面,只返回接口数据。适用于前后端分离系统。
示例
java
@Controller
public class UserController {
// 1. 返回页面(templates/index.html)
@GetMapping("/index")
public String index() {
return "index"; // 找页面
}
// 2. 返回JSON → 必须加 @ResponseBody
@GetMapping("/user")
@ResponseBody
public User getUser() {
return new User();
}
}
java
@RestController // 自带 @ResponseBody
public class UserApiController {
// 直接返回 JSON,不用加任何注解
@GetMapping("/user")
public User getUser() {
return new User();
}
}
实现一个简单的hello api

注意这里面@RestController和@RequestMapping缺一不可。
访问路径
bash
localhost:8080/hello

这里如果在类上加@RequstMapping注解,则需要增加访问地址前缀,访问路径:
bash
localhost:8080/index/hello
这是该类上的统一前缀,如果需要整个项目添加统一前缀,则在application.yml文件中添加。
访问路径:
bash
http://localhost:8080/api/index/hello
SpringMVC实现Restfulapi请求方法

url中只写资源名称而不写动作。
Get请求


如果要反复使用@Getmapping,其所带参数需不一致,否则报错。
Post请求
post请求携带请求体,前后端分离系统一般携带JSON格式数据。

这里注解使用@RequestBody来接收Json数据。
Put请求

Delete请求

上面Json形式数据需用postman来进行测试
SpringBoot多环境配置
原本我们只有一份配置文件

现在我们变成三份配置文件,一份开发环境,一份生产环境,一份设置默认环境。



三层架构的概念
经典的Controller,Service,Mapper(Dao)三层架构

SpringBoot整合Mybatis-Plus
我们先创建一个数据库,再创建一个表。
这里我直接使用Mybatis-Plus官方文档中内容进行创建如图

之后我们在pom.xml中添加Mybatis-Plus和mysql依赖

之后在application-dev.yml文件中配置mysql

我们创建mapper目录后再补充mybatis-plus相关配置如下图

之后在启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹

之后我们添加以下lombok依赖,方便我们实体类的创建。

之后创建entity包,创建User类

之后创建Mapper接口

通一下逻辑
mybatis-plus在项目启动时会根据MapperScan注解来寻找Mapper接口并且实例化放入IOC容器中,@Autowired或@Resource从容器中获取对象。
下面是测试代码

运行时可能遇到IDEA版本、SpringBoot版本、lombok版本冲突问题,结合ai自行解决即可。
下图是运行成功截图

通过继承Mybatis-Plus通用Service实现自己的Service类
在Service包中构建下图所示结构

UserService见下图

impl中我们要实现每个方法,但是太麻烦了

我们可以直接继承Mybatis提供的实现类

具体的方法可查看Mybatis官方文档

下图是测试通过

使用SpringMvc实现增删改查api接口
我们先创建common包并创建Result类

类中代码如下
java
package com.ittao.demo_6_2.common;
import com.sun.net.httpserver.Authenticator;
import lombok.Data;
import java.io.Serializable;
@Data
public class Result implements Serializable {
private static final long serialVersionUID = 1L;
private String code;
private String message;
private Object data;
/**
* 直接返回成功结果
* @param data 获取的数据
* @return
*/
public static Result success(Object data) {
return success("200", "操作成功", data);
}
/**
* 自定义返回成功结果
* @param code 状态码
* @param message 提示信息
* @param data 获取的数据
* @return
*/
public static Result success(String code, String message, Object data) {
Result result = new Result();
result.setCode(code);
result.setMessage(message);
result.setData(data);
return result;
}
/**
* 不带结果直接返回成功
* @return
*/
public static Result success(){
Result result = new Result();
result.setCode("200");
result.setMessage("操作成功");
return result;
}
/**
* 直接返回失败信息
* @return
*/
public static Result error(){
return error("400", "操作失败",null);
}
/**
* 自定义返回失败信息
* @param code 状态码
* @param message 提示信息
* @param data 获取的数据
* @return
*/
public static Result error(String code, String message, Object data) {
Result result = new Result();
result.setCode(code);
result.setMessage(message);
result.setData(data);
return result;
}
/**
* 带参数返回失败信息
* @param message 提示信息
* @return
*/
public static Result error(String message){
return error("400", message, null);
}
}
之后我们就可以完成Controller部分内容,代码见下面
java
package com.ittao.demo_6_2.controller;
import com.ittao.demo_6_2.common.Result;
import com.ittao.demo_6_2.entity.User;
import com.ittao.demo_6_2.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
/**
* 新增用户
* @param user
* @return
*/
@PostMapping
public Result save(@RequestBody User user) {
userService.save(user);
return Result.success();
}
/**
* 修改用户
* @param user
* @return
*/
@PutMapping
public Result update(@RequestBody User user) {
userService.updateById(user);
return Result.success();
}
/**
* 查询单个用户
* @param id
* @return
*/
@GetMapping("/{id}")
public Result getOne(@PathVariable Integer id) {
return Result.success(userService.getById(id));
}
/**
* 查询所有用户
* @return
*/
@GetMapping
public Result findAll() {
return Result.success(userService.list());
}
/**
* 删除用户
* @param id
* @return
*/
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
userService.removeById(id);
return Result.success();
}
}
之后我们用Postman测试即可
整合Mybatis-Plus分页插件并实现分页api方法
我们在userController文件中新增分页查询接口,代码如下
java
/**
* 分页查询
* @param pageNum
* @param pageSize
* @return
*/
@GetMapping("/page")
public Result findPage(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "10") Integer pageSize){
return Result.success(
userService.page(new Page<>(pageNum,pageSize))
);
}
测试结果如下

这里我们看到设置了pageSize=2但并没有生效,这是因为在Mybatis-Plus中要使用分页功能,需要在SpringBoot中注入插件对象。
我们直接查看Mybatis-plus文档,搜索分页插件。

创建config包,创建MybatisPlusConfig类,粘贴文档中配置代码,并将启动类中MapperScan移到该类上方

接下来我们引入Maven bom依赖


之后就可以正常在配置类中进行导入。
现在可以正常分页了,见下图

拓展:@bean只是创建bean的一种方式,大部分时候我们不用 @Bean,而是用 @Service / @Controller.
① 什么时候用 @Service / @Component?
自己写的类 → 直接加在类上
② 什么时候用 @Bean?
别人写的类、第三方类 → 在配置类里写方法创建
- 接收前端请求 → `@Controller` 2. 写业务逻辑 → `@Service` 3. 操作数据库 → `@Repository` 4. 通用工具、辅助类 → `@Component`
- 自己写的源码类 → 类上加 `@Component` 系列 - 第三方jar包里的类(你不能修改源码) → 配置类中用 `@Bean` 方法创建Bean
Mybatis-plus实现数据的自动填充
首先在数据库中创建字段

之后修改实体类,添加这两个属性。
但是代码中我们习惯用驼峰,与数据库中字段不一致,我们可以用@TableField注解添加value,并且添加fill属性。

之后我们创建Handler包并创建类

完成后重启项目即可,测试用Postman发送请求。
这里拓展一下,我们可以使用JsonFormat注解来指定自动填充的时间格式。

Mybatis-Plus实现条件查询
我们以findPage方法进行演示

测试结果如下

SpringBoot整合Redis
首先添加redis依赖和redis连接池依赖

这样引入后,启动时依赖对应的类就会往springboot容器中注入redis的操作对象------redistemplate,我们就能直接使用。但原生配置的对象不好用,我们习惯用getkey和setkey方法,因此我们需要相关配置。
我们先在配置文件中加入redis相关

之后我们创建redisConfig类,代码如下
java
@Configuration
public class RedisConfig {
@Value("${spring.data.redis.host}")
private String redisHost;
@Value("${spring.data.redis.port}")
private int redisPort;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(redisHost, redisPort);
return new LettuceConnectionFactory(config);
}
@SuppressWarnings("removal")
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory Factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(Factory);
//设置key和hashKey使用字符串序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
//设置Jackson2JsonRedisSerializer作为value序列化方式
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.activateDefaultTyping(
LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.PROPERTY
);
jackson2JsonRedisSerializer.setObjectMapper(mapper);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
}
之后创建util包,并创建RedisUtil工具类。代码如下
java
package com.ittao.demo_6_2.util;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
public class RedisUtil {
@Resource
private RedisTemplate<String, Object> redisTemplate;
/*** 通用操作 ***/
public boolean expire(String key, long time){
try{
if(time>0){
redisTemplate.expire(key,time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public long getExpire(String key){
return redisTemplate.getExpire(key,TimeUnit.SECONDS);
}
public boolean hasKey(String key){
try{
return redisTemplate.hasKey(key);
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public void del(String... keys){
if(keys!=null && keys.length>0){
if(keys.length==1){
redisTemplate.delete(keys[0]);
} else{
redisTemplate.delete(CollectionUtils.arrayToList(keys).toString());
}
}
}
/*** String操作 ***/
public Object get(String key){
return key==null?null:redisTemplate.opsForValue().get(key);
}
public boolean set(String key, Object value){
try{
redisTemplate.opsForValue().set(key,value);
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public boolean set(String key, Object value, long time){
try{
if(time>0){
redisTemplate.opsForValue().set(key,value,time,TimeUnit.SECONDS);
} else{
set(key,value);
}
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public long incr(String key, long delta){
if(delta<0){
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key,delta);
}
public long decr(String key, long delta){
if(delta<0){
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key,-delta);
}
/*** Hash操作 ***/
public Object hGet(String key, String item){
return redisTemplate.opsForHash().get(key,item);
}
public Map<Object,Object> hmGet(String key){
return redisTemplate.opsForHash().entries(key);
}
public boolean hmSet(String key, Map<String,Object> map){
try{
redisTemplate.opsForHash().putAll(key,map);
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public boolean hmSet(String key, Map<String,Object> map, long time){
try{
redisTemplate.opsForHash().putAll(key,map);
if(time>0){
expire(key,time);
}
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public boolean hSet(String key, String item, Object value){
try{
redisTemplate.opsForHash().put(key,item,value);
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public boolean hSet(String key, String item, Object value, long time){
try{
redisTemplate.opsForHash().put(key,item,value);
if(time>0){
expire(key,time);
}
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public void hDel(String key, Object... item){
redisTemplate.opsForHash().delete(key,item);
}
public boolean hHasKey(String key, String item){
return redisTemplate.opsForHash().hasKey(key,item);
}
public double hIncr(String key, String item, double by){
return redisTemplate.opsForHash().increment(key,item,by);
}
public double hDecr(String key, String item, double by){
return redisTemplate.opsForHash().increment(key,item,-by);
}
/*** Set操作 ***/
public Set<Object> sMembers(String key){
return redisTemplate.opsForSet().members(key);
}
public boolean sHasKey(String key, Object value){
return redisTemplate.opsForSet().isMember(key,value);
}
public long sSet(String key, Object... values){
try{
return redisTemplate.opsForSet().add(key,values);
} catch (Exception e){
e.printStackTrace();
return 0;
}
}
public long sSet(String key, long time, Object... values){
try{
Long count = redisTemplate.opsForSet().add(key,values);
if(time>0){
expire(key,time);
}
return count;
} catch (Exception e){
e.printStackTrace();
return 0;
}
}
public long sGetSetSize(String key){
try{
return redisTemplate.opsForSet().size(key);
} catch (Exception e){
e.printStackTrace();
return 0;
}
}
public long setRemove(String key, Object... values){
try{
Long count = redisTemplate.opsForSet().remove(key,values);
return count;
} catch (Exception e){
e.printStackTrace();
return 0;
}
}
/*** List操作 ***/
public List<Object> lGet(String key, long start, long end){
try{
return redisTemplate.opsForList().range(key,start,end);
} catch (Exception e){
e.printStackTrace();
return null;
}
}
public long lGetListSize(String key){
try{
return redisTemplate.opsForList().size(key);
} catch (Exception e){
e.printStackTrace();
return 0;
}
}
public Object lGetIndex(String key, long index){
try{
return redisTemplate.opsForList().index(key,index);
} catch (Exception e){
e.printStackTrace();
return null;
}
}
public boolean lSet(String key, Object value){
try{
redisTemplate.opsForList().rightPush(key,value);
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public boolean lSet(String key, Object value, long time){
try{
redisTemplate.opsForList().rightPush(key,value);
if(time>0){
expire(key,time);
}
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public boolean lSetAll(String key, List<Object> value){
try{
redisTemplate.opsForList().rightPushAll(key,value);
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public boolean lSetAll(String key, List<Object> value, long time){
try{
redisTemplate.opsForList().rightPushAll(key,value);
if(time>0){
expire(key,time);
}
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public boolean lUpdateIndex(String key, long index, Object value){
try{
redisTemplate.opsForList().set(key,index,value);
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public long lRemove(String key, long count, Object value){
try{
Long remove = redisTemplate.opsForList().remove(key,count,value);
return remove;
} catch (Exception e){
e.printStackTrace();
return 0;
}
}
/*** ZSet操作 ***/
public boolean zSet(String key, Object value, double score){
try{
redisTemplate.opsForZSet().add(key,value,score);
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public boolean zSet(String key, Object value, double score, long time){
try{
Boolean result = redisTemplate.opsForZSet().add(key,value,score);
if(time>0){
expire(key,time);
}
return result;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public Set<Object> zGet(String key, double min, double max){
try{
return redisTemplate.opsForZSet().rangeByScore(key,min,max);
} catch (Exception e){
e.printStackTrace();
return null;
}
}
public long zRemove(String key, Object... values){
try{
Long count = redisTemplate.opsForZSet().remove(key,values);
return count;
} catch (Exception e){
e.printStackTrace();
return 0;
}
}
/*** 原子操作 ***/
public boolean setNx(String key, Object value){
try{
return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key,value));
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public boolean setNx(String key, Object value, long time){
try{
Boolean result = redisTemplate.opsForValue().setIfAbsent(key,value,time,TimeUnit.SECONDS);
return Boolean.TRUE.equals(result);
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public boolean setXx(String key, Object value){
try{
return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfPresent(key,value));
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public boolean setXx(String key, Object value, long time){
try{
Boolean result = redisTemplate.opsForValue().setIfPresent(key,value,time,TimeUnit.SECONDS);
return Boolean.TRUE.equals(result);
} catch (Exception e){
e.printStackTrace();
return false;
}
}
public long incrByAtomic(String key, long delta){
try{
return redisTemplate.opsForValue().increment(key,delta);
} catch (Exception e){
e.printStackTrace();
return 0;
}
}
public double incrByFloat(String key, double delta){
try{
return redisTemplate.opsForValue().increment(key,delta);
} catch (Exception e){
e.printStackTrace();
return 0;
}
}
public boolean append(String key, String value){
try{
redisTemplate.opsForValue().append(key,value);
return true;
} catch (Exception e){
e.printStackTrace();
return false;
}
}
}
之后我们用navacat连接上redis,去测试类进行测试。
跑通后即可看到数据
