springboot +mybatis-plus 代码

【0】工程结构

在这里插入图片描述
TempController请忽略。
在这里插入图片描述
在这里插入图片描述

【1】数据库文件

CREATE DATABASE IF NOT EXISTS `mp` 
USE `mp`;

drop table `address`;

CREATE TABLE IF NOT EXISTS `address` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `user_id` bigint DEFAULT NULL COMMENT '用户ID',
  `province` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '省',
  `city` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '市',
  `town` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '县/区',
  `mobile` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '手机',
  `street` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '详细地址',
  `contact` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '联系人',
  `is_default` bit(1) DEFAULT b'0' COMMENT '是否是默认 1默认 0否',
  `notes` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '备注',
  `deleted` bit(1) DEFAULT b'0' COMMENT '逻辑删除',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `user_id` (`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=71 DEFAULT CHARSET=utf8mb3 ROW_FORMAT=COMPACT;

alter table address add COLUMN `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间';
alter table address add COLUMN `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间';


INSERT INTO `address` (`id`, `user_id`, `province`, `city`, `town`, `mobile`, `street`, `contact`, `is_default`, `notes`, `deleted`) VALUES
	(59, 2, '北京', '北京', '朝阳区', '13900112222', '金燕龙办公楼', 'Rose', b'1', NULL, b'0'),
	(60, 1, '北京', '北京', '朝阳区', '13700221122', '修正大厦', 'Jack', b'0', NULL, b'0'),
	(61, 1, '上海', '上海', '浦东新区', '13301212233', '航头镇航头路', 'Jack', b'1', NULL, b'0'),
	(63, 2, '广东', '佛山', '永春', '13301212233', '永春武馆', 'Rose', b'0', NULL, b'0'),
	(64, 3, '浙江', '杭州', '拱墅区', '13567809102', '浙江大学', 'Hope', b'1', NULL, b'0'),
	(65, 3, '浙江', '杭州', '拱墅区', '13967589201', '左岸花园', 'Hope', b'0', NULL, b'0'),
	(66, 4, '湖北', '武汉', '汉口', '13967519202', '天天花园', 'Thomas', b'1', NULL, b'0'),
	(67, 3, '浙江', '杭州', '拱墅区', '13967589201', '左岸花园', 'Hopey', b'0', NULL, b'0'),
	(68, 4, '湖北', '武汉', '汉口', '13967519202', '天天花园', 'Thomas', b'1', NULL, b'0'),
	(69, 3, '浙江', '杭州', '拱墅区', '13967589201', '左岸花园', 'Hopey', b'0', NULL, b'0'),
	(70, 4, '湖北', '武汉', '汉口', '13967519202', '天天花园', 'Thomas', b'1', NULL, b'0');

drop table `user`;
CREATE TABLE IF NOT EXISTS `user` (
	`id` BIGINT(19) NOT NULL AUTO_INCREMENT COMMENT '用户id',
	`username` VARCHAR(50) NOT NULL COMMENT '用户名' COLLATE 'utf8_general_ci',
	`password` VARCHAR(128) NOT NULL COMMENT '密码' COLLATE 'utf8_general_ci',
	`phone` VARCHAR(20) NULL DEFAULT NULL COMMENT '注册手机号' COLLATE 'utf8_general_ci',
	`info` JSON NOT NULL COMMENT '详细信息',
	`status` INT(10) NULL DEFAULT '1' COMMENT '使用状态(1正常 2冻结)',
	`balance` INT(10) NULL DEFAULT NULL COMMENT '账户余额',
	`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
	`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
	 `deleted` bit(1) DEFAULT b'0' COMMENT '逻辑删除',
	PRIMARY KEY (`id`) USING BTREE,
	UNIQUE INDEX `username` (`username`) USING BTREE
)
COMMENT='用户表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
ROW_FORMAT=COMPACT
AUTO_INCREMENT=5
;

INSERT INTO `user` (`id`, `username`, `password`, `phone`, `info`, `status`, `balance`, `create_time`, `update_time`) VALUES
	(1, 'Jack', '123', '13900112224', '{"age": 20, "intro": "佛系青年", "gender": "male"}', 1, 1600, '2023-05-19 20:50:21', '2023-06-19 20:50:21'),
	(2, 'Rose', '123', '13900112223', '{"age": 19, "intro": "青涩少女", "gender": "female"}', 1, 600, '2023-05-19 21:00:23', '2023-06-19 21:00:23'),
	(3, 'Hope', '123', '13900112222', '{"age": 25, "intro": "上进青年", "gender": "male"}', 1, 100000, '2023-06-19 22:37:44', '2023-06-19 22:37:44'),
	(4, 'Thomas', '123', '17701265258', '{"age": 29, "intro": "伏地魔", "gender": "male"}', 1, 800, '2023-06-19 23:44:45', '2023-06-19 23:44:45');

【2】pom.xml(注意版本兼容问题…)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.9</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gina</groupId>
    <artifactId>mybatis-plus-04-generator</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mybatis-plus-04-generator</name>
    <description>mybatis-plus-04-generator</description>
    <properties>
        <java.version>17</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.5</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.33</version>
        </dependency>

        <!--基于knife4j-openapi3的api接口文档生成-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
            <version>4.4.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.20</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

【3】配置文件:application.yml

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/mp?rewriteBatchedStatements=true
    driver-class-name: com.mysql.cj.jdbc.Driver
#  main:
#    banner-mode: off #关闭SpringBoot启动图标(banner)

# mp日志,打印SQL日志到控制台
mybatis-plus:
  type-aliases-package: com.gina.entity #别名扫描包
  mapper-locations: classpath*:/mapper/**/*.xml #Mapper.xml文件地址,用来写复杂sql
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #在控制台打印sql
    map-underscore-to-camel-case: true #开启下划线和驼峰的映射
    cache-enabled: false #是否开启二级缓存
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
  global-config:
    banner: false # 关闭mybatisplus启动图标
    db-config:
      id-type: auto #id生成策略。如果注解没有配置吗,则用此全局配置
      update-strategy: not_null #更新策略 updateById(),默认只更新非空字段
      logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

# springdoc-openapi项目配置
springdoc:
  swagger-ui:
    path: /swagger-ui.html
    tags-sorter: alpha
    operations-sorter: alpha
  api-docs:
    path: /v3/api-docs
  group-configs:
    - group: 'default'
      paths-to-match: '/**'
      packages-to-scan: com.gina.controller

# knife4j的增强配置,不需要增强可以不配
knife4j:
  enable: true
  setting:
    language: zh_cn

【4】config

@Configuration
public class MybatisConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        //0.初始化MybatisPlus拦截器核心插件
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //1.添加分页插件 PaginationInnerInterceptor
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        paginationInnerInterceptor.setMaxLimit(1000L);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        //2.添加乐观锁拦截器
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}
@Configuration
public class SwaggerConfig {
    @Bean
    public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() {
        return openApi -> {
            if (openApi.getTags() != null) {
                openApi.getTags().forEach(tag -> {
                    Map<String, Object> map = new HashMap<>();
                    map.put("x-order", RandomUtil.randomInt(0, 100));
                    tag.setExtensions(map);
                });
            }
            if (openApi.getPaths() != null) {
                openApi.addExtension("x-test123", "333");
                openApi.getPaths().addExtension("x-abb", RandomUtil.randomInt(1, 100));
            }

        };
    }
    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
                .info(new Info()
                        .title("用户管理接口文档")
                        .version("1.0")
                        .description("这是root的用户管理接口文档test...")
                        .termsOfService("http://doc.xiaominfo.com")
                        .license(new License().name("Apache 2.0")
                                .url("http://doc.xiaominfo.com")));
    }
}

【5】controller

@RestController
@RequestMapping("/user")
@Tag(name = "用户管理接口")
@RequiredArgsConstructor
public class UserController {
    private final IUserService userService;

    /**
     * 新增1条
     */
    @PostMapping
    @Operation(summary = "新增单个用户", description = "根据提交的用户表单实体创建用户")
    public ResponseEntity<String> saveUser(@RequestBody UserFormDTO userFormDTO) {
        // 1.转换DTO为PO
        User user = BeanUtil.copyProperties(userFormDTO, User.class);
        // 2.新增
        if (userService.save(user)) {
            return new ResponseEntity<>("新增成功!", HttpStatus.CREATED);
        } else {
            return new ResponseEntity<>("新增失败!", HttpStatus.BAD_REQUEST);
        }
    }

    @DeleteMapping("/{id}")
    @Operation(summary = "删除单个用户", description = "根据id删除用户")
    @Parameters({@Parameter(name = "id", description = "用户id", required = true, in = ParameterIn.PATH)})
    public ResponseEntity<String> removeUserById(@PathVariable("id") Long userId) {
        if (userService.removeById(userId)) {
            return new ResponseEntity<>("删除成功!", HttpStatus.OK);
        } else {
            return new ResponseEntity<>("删除失败!", HttpStatus.BAD_REQUEST);
        }
    }

    //改造
    @GetMapping("/{id}")
    @Operation(summary = "查询单个用户", description = "根据id查询用户,并查询出用户对应的所有地址")
    @Parameters({@Parameter(name = "id", description = "用户id", required = true, in = ParameterIn.PATH)})
    public ResponseEntity<UserVO> queryUserById(@PathVariable("id") Long userId) {
        // 1.查询用户
        UserVO userVo = userService.queryUserAndAddressById(userId);
        // 2.处理vo
        if (userVo != null) {
            return new ResponseEntity<>(BeanUtil.copyProperties(userVo, UserVO.class), HttpStatus.OK);
        } else {
            return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
        }
    }

    @GetMapping
    @Operation(summary = "查询用户集合", description = "根据id批量查询用户,并查询出用户对应的所有地址")
    @Parameters({@Parameter(name = "ids", description = "用户id集合", required = true, in = ParameterIn.QUERY)})
    public ResponseEntity<List<UserVO>> queryUserByIds(@RequestParam("ids") List<Long> ids) {
        // 1.查询用户
        List<UserVO> users = userService.queryUserAndAddressByIds(ids);
        // 2.处理vo
        if (users != null) {
            return new ResponseEntity<>(users, HttpStatus.OK);
        } else {
            return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
        }
    }

    @PutMapping("{id}/deduction/{money}")
    @Operation(summary = "扣钱", description = "根据id扣减用户余额接口")
    @Parameters({@Parameter(name = "id", description = "用户id", required = true, in = ParameterIn.PATH),
            @Parameter(name = "money", description = "扣除金额", required = true, in = ParameterIn.PATH)})
    public ResponseEntity<Boolean> deductBalance(@PathVariable("id") Long id, @PathVariable("money") Integer money) {

        if (userService.deductBalance(id, money)) {
            return new ResponseEntity<>(true, HttpStatus.CREATED);
        } else {
            return new ResponseEntity<>(false, HttpStatus.BAD_REQUEST);
        }
    }


    @GetMapping("/queryUserByIdAndAddr")
    @Operation(summary = "根据id集合和某个city查询用户", description = "根据id集合和某个city查询用户接口")
    @Parameters({@Parameter(name = "ids", description = "用户id集合", required = true, in = ParameterIn.QUERY),
            @Parameter(name = "city", description = "用户城市", required = true, in = ParameterIn.QUERY)})
    public ResponseEntity<List<UserVO>> queryUserByIdAndAddr(@RequestParam("ids") List<Long> ids, @RequestParam("city") String city) {
        List<User> userList = userService.queryUserByIdAndAddr(ids, city);
        List<UserVO> userVOList = BeanUtil.copyToList(userList, UserVO.class);
        if (userList != null) {
            return new ResponseEntity<>(userVOList, HttpStatus.OK);
        } else {
            return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
        }
    }

    @PostMapping("/saveBatch")
    @Operation(summary = "批量新增用户", description = "根据多个用户表单实体新增用户")
    public ResponseEntity<String> saveBatch(@RequestBody List<UserFormDTO> userFormDTOList) {
        List<User> usersList = BeanUtil.copyToList(userFormDTOList, User.class);
        if (userService.saveBatch(usersList)) {
            return new ResponseEntity<>("批量新增数据成功!", HttpStatus.CREATED);
        } else {
            return new ResponseEntity<>("批量新增数据失败.....", HttpStatus.BAD_REQUEST);
        }
    }


    @PostMapping("/saveOrUpdate")
    @Operation(summary = "新增或修改用户", description = "新增或修改用户,有则修改,无则增加")
    public ResponseEntity<String> saveOrUpdate(@RequestBody UserFormDTO userFormDTO) {
        User user = BeanUtil.copyProperties(userFormDTO, User.class);
        if (userService.saveOrUpdate(user)) {
            return new ResponseEntity<>("新增or修改成功!", HttpStatus.CREATED);
        } else {
            return new ResponseEntity<>("新增or修改失败...", HttpStatus.BAD_REQUEST);
        }
    }


    @PostMapping("/saveOrUpdateBatch")
    @Operation(summary = "批量新增或修改用户", description = "批量新增或修改用户,有则修改,无则增加")
    public ResponseEntity<String> saveOrUpdateBatch(@RequestBody List<UserFormDTO> userFormDTOList) {
        List<User> usersList = BeanUtil.copyToList(userFormDTOList, User.class);
        if (userService.saveOrUpdateBatch(usersList)) {
            return new ResponseEntity<>("批量新增or修改成功!", HttpStatus.CREATED);
        } else {
            return new ResponseEntity<>("批量新增or修改失败....", HttpStatus.BAD_REQUEST);
        }
    }


    /**
     * 用户查询条件实体来实现
     */
    @PostMapping("/queryUserByNameStatusBalance")
    @Operation(summary = "根据名字、状态、最小金额、最大金额查询用户", description = "根据名字、状态、最小金额、最大金额查询用户,条件可能为空值")
    public ResponseEntity<List<UserVO>> queryUserByNameStatusBalance(@RequestBody UserQuery userQuery) {
        List<User> userList = userService.queryUserByNameStatusBalance(userQuery.getName(), userQuery.getStatus(),
                userQuery.getMinBalance(), userQuery.getMaxBalance());

        List<UserVO> userVOS = BeanUtil.copyToList(userList, UserVO.class);

        if (userVOS != null) {
            return new ResponseEntity<>(userVOS, HttpStatus.OK);
        } else {
            return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
        }
    }

    /**
     * 分页查询
     */
    @PostMapping("/queryUserPage")
    @Operation(summary = "分页查询用户", description = "分页查询用户")
    public ResponseEntity<PageDTO<UserVO>> queryUserPage(@RequestBody UserQuery userQuery) {
        PageDTO<UserVO> userPageDTO = userService.queryUserPage(userQuery);
        if (userPageDTO != null) {
            return new ResponseEntity<>(userPageDTO, HttpStatus.OK);
        } else {
            return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
        }
    }
}
@RestController
@RequestMapping("/address")
@Tag(name = "地址管理接口")
@RequiredArgsConstructor
public class AddressController {
    private final IAddressService addressService;

    @PostMapping
    @Operation(summary = "新增地址", description = "新增地址")
    public ResponseEntity<String> save(@RequestBody AddressDTO addressDTO) {
        final Address address = BeanUtil.copyProperties(addressDTO, Address.class);
        if (addressService.save(address)) {
            return new ResponseEntity<>("新增地址成功!", HttpStatus.CREATED);
        } else {
            return new ResponseEntity<>("新增地址失败!", HttpStatus.BAD_REQUEST);
        }
    }


    @DeleteMapping("/{id}")
    @Operation(summary = "删除地址", description = "根据地址id删除地址")
    @Parameters({@Parameter(name = "id", description = "地址id", required = true, in = ParameterIn.PATH)})
    public ResponseEntity<String> removeUserById(@PathVariable("id") Long addId) {
        if (addressService.removeById(addId)) {
            return new ResponseEntity<>("删除成功!", HttpStatus.OK);
        } else {
            return new ResponseEntity<>("删除失败!", HttpStatus.BAD_REQUEST);
        }
    }

    @GetMapping("/{id}")
    @Operation(summary = "根据地址id查询地址", description = "根据地址id查询地址")
    public ResponseEntity<AddressVO> getAddressById(@PathVariable("id") Long addId) {
        final AddressVO address = BeanUtil.copyProperties(addressService.getById(addId), AddressVO.class);
        if (address != null) {
            return new ResponseEntity<>(address, HttpStatus.CREATED);
        } else {
            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
        }
    }

    /**
     * 根据省市县查询地址list
     */
    @PostMapping("/getaAddressWithProvince")
    @Operation(summary = "根据收货地址查用户", description = "查询收货地址在某province的所有地址,及其用户")
    public ResponseEntity<PageDTO<AddressVO>> getaAddressWithProvince(@RequestBody AddressQuery addressQuery) {
        PageDTO<AddressVO> addressPageDTO = addressService.getaAddressWithProvince(addressQuery);
        if (addressPageDTO != null) {
            return new ResponseEntity<>(addressPageDTO, HttpStatus.OK);
        } else {
            return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
        }
    }
}

【6】entity

DTO

@Data
@Schema(description = "分页结果")
@AllArgsConstructor
@NoArgsConstructor
public class PageDTO<T> {
    @Schema(title = "total", description = "总条数")
    private Long total;
    @Schema(title = "pages", description = "总页数")
    private Long pages;
    @Schema(title = "list", description = "集合")
    private List<T> list;

    public static <VO, PO> PageDTO<VO> of(Page<PO> page, Class<VO> clazz) {
        //3.参数非空校验
        //获取当页数据
        List<PO> records = CollUtil.isEmpty(page.getRecords()) ?
                Collections.emptyList() : page.getRecords();
        //4.有数据,转换
        List<VO> userVOList = BeanUtil.copyToList(records, clazz);
        return new PageDTO<>(page.getTotal(), page.getPages(), userVOList);
    }

    public static <VO, PO> PageDTO<VO> ofMyself(Page<PO> page, Function<PO, VO> convertor) {
        //3.参数非空校验
        //获取当页数据
        List<PO> records = CollUtil.isEmpty(page.getRecords()) ?
                Collections.emptyList() : page.getRecords();
        //4.有数据,转换
        PageDTO<VO> objectPageDTO = new PageDTO<>();
        List<VO> userVOList = records.stream().map(convertor).collect(Collectors.toList());

        objectPageDTO.setPages(page.getPages());
        objectPageDTO.setTotal(page.getTotal());
        objectPageDTO.setList(userVOList);

        return objectPageDTO;
    }
}
@Data
@Schema(description = "用户表单实体")//- UserFormDTO:代表新增时的用户表单
public class UserFormDTO {
    @Schema(title = "id", description = "主键id", defaultValue = "0")
    private Long id;

    @Schema(title = "username", description = "用户名")
    private String username;

    @Schema(title = "password", description = "密码")
    private String password;

    @Schema(title = "phone", description = "注册手机号")
    private String phone;

    @Schema(title = "info", description = "详细信息,JSON风格")
    private UserInfo info;

    @Schema(title = "balance", description = "账户余额")
    private Integer balance;
}

@Data
@Schema(description = "地址表单实体")//- UserFormDTO:代表新增时的用户表单
public class AddressDTO {

    @Schema(title = "province", description = "省")
    private String province;

    @Schema(title = "city", description = "市")
    private String city;

    @Schema(title = "town", description = "县/区")
    private String town;
}

PO

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName(value = "user", autoResultMap = true)
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 用户id
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;

    /**
     * 注册手机号
     */
    private String phone;

    /**
     * 详细信息
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    private UserInfo info;

    /**
     * 使用状态(1正常 2冻结)
     */
    private UserStatus status;

    /**
     * 账户余额
     */
    private Integer balance;

    /**
     * 创建时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    /**
     * 更新时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;

    /**
     * 逻辑删除
     */
    private Boolean deleted;
}

@Data
@NoArgsConstructor
@AllArgsConstructor(staticName = "of")//用静态方法更加语义化地创建 User 类的实例。
public class UserInfo {
    private Integer age;
    private String intro;
    private String gender;
}

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("address")
public class Address implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 用户ID
     */
    private Long userId;

    /**
     * 省
     */
    private String province;

    /**
     * 市
     */
    private String city;

    /**
     * 县/区
     */
    private String town;

    /**
     * 手机
     */
    private String mobile;

    /**
     * 详细地址
     */
    private String street;

    /**
     * 联系人
     */
    private String contact;

    /**
     * 是否是默认 1默认 0否
     */
    private AddressStatus isDefault;

    /**
     * 备注
     */
    private String notes;

    /**
     * 逻辑删除
     */
    private Boolean deleted;

    /**
     * 创建时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    /**
     * 更新时间
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;

}

query

@Data
@Schema(description = "分页查询实体")
public class PageQuery {
    @Schema(title = "pageNo", description = "页码")
    private Long pageNo = 1L;
    @Schema(title = "pageSize", description = "页码")
    private Long pageSize = 5L;
    @Schema(title = "sortBy", description = "排序字段")
    private String sortBy;
    @Schema(title = "isAsc", description = "是否升序")
    private Boolean isAsc = true;

    public <T> Page<T> toMpPage(Boolean isAsc, String... sortByColumns) {
        // 1构建条件
        // 1.1分页条件
        Page<T> page = Page.of(pageNo, pageSize);
        // 1.2.排序条件
        if (this.sortBy != null) {
            OrderItem orderItem = new OrderItem().setColumn(this.sortBy).setAsc(this.isAsc);
            page.addOrder(orderItem);
        } else if (sortByColumns != null) {
            //默认排序字段不确定
            OrderItem orderItem = new OrderItem().setAsc(isAsc);
            for (String s : sortByColumns) {
                orderItem.setColumn(s);
            }
            page.addOrder(orderItem);
        }
        return page;
    }

    public <T> Page<T> toMpPage(String defaultSortBy, boolean isAsc) {
        return this.toMpPage(isAsc, defaultSortBy);
    }

    public <T> Page<T> toMpPageDefaultSortByCreateTimeDesc() {
        return toMpPage("create_time", false);
    }

    public <T> Page<T> toMpPageDefaultSortByUpdateTimeDesc() {
        return toMpPage("update_time", false);
    }
}
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(description = "用户查询条件实体")
public class UserQuery extends PageQuery {
    @Schema(title = "name", description = "用户名关键字")
    private String name = null;

    @Schema(title = "status", description = "用户状态:1-正常,2-冻结")
    private UserStatus status = null;

    @Schema(title = "minBalance", description = "余额最小值")
    private Integer minBalance = null;

    @Schema(title = "maxBalance", description = "余额最大值")
    private Integer maxBalance = null;
}
@EqualsAndHashCode(callSuper = true)
@Data
@Schema(description = "地址查询条件实体")
public class AddressQuery extends PageQuery{

    @Schema(title = "province", description = "省")
    private String province;

    @Schema(title = "city", description = "市")
    private String city;

    @Schema(title = "town", description = "县/区")
    private String town;
}

vo

@Data
@Schema(description = "用户VO实体")//- UserVO:代表查询的返回结果
public class UserVO {
    @Schema(title = "id", description = "主键id", defaultValue = "0")
    private Long id;

    @Schema(title = "username", description = "用户名")
    private String username;

    @Schema(title = "info", description = "详细信息")
    private UserInfo info;

    @Schema(title = "status", description = "使用状态(1正常 2冻结)")
    private UserStatus status;

    @Schema(title = "balance", description = "账户余额")
    private Integer balance;

    @Schema(title = "addressList", description = "收货地址列表")
    private List<AddressVO> addressList;
}

@Data
@Schema(description = "收货地址VO")
public class AddressVO{
    @Schema(title = "id", description = "主键id")
    private Long id;

    @Schema(title = "userId", description = "用户ID")
    private Long userId;

    @Schema(title = "province", description = "省")
    private String province;

    @Schema(title = "city", description = "市")
    private String city;

    @Schema(title = "town", description = "县/区")
    private String town;

    @Schema(title = "mobile", description = "手机")
    private String mobile;

    @Schema(title = "street", description = "详细地址")
    private String street;

    @Schema(title = "contact", description = "联系人")
    private String contact;

    @Schema(title = "isDefault", description = "是否是默认 1默认 0否")
    private AddressStatus isDefault;

    @Schema(title = "notes", description = "备注")
    private String notes;

    @Schema(title = "userVO", description = "用户所有信息")
    private UserVO userVO;
}

【7】enums

@Getter
public enum AddressStatus {

    DEFAULT(1,"默认"),
    NOT_DEFAULT(0,"非默认");

    @EnumValue//在需要保存到数据库的值上面加上注解
    private final int value;
    @JsonValue//需要在前端展示哪个值就在哪个属性上加上该注解
    private final String desc;

    AddressStatus(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }
}
@Getter
public enum UserStatus {
    NORMAL(1, "正常"),
    FREEZE(2, "冻结");

    @EnumValue//在需要保存到数据库的值上面加上注解
    private final int value;

    @JsonValue//需要在前端展示哪个值就在哪个属性上加上该注解
    private final String desc;

    UserStatus(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }
}

【8】mapper

@Mapper
public interface AddressMapper extends BaseMapper<Address> {

}
<?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.gina.mapper.AddressMapper">
</mapper>
@Mapper
public interface UserMapper extends BaseMapper<User> {
    @Select("SELECT * FROM user  INNER JOIN address  ON user.id = address.user_id ${ew.customSqlSegment}")
    List<User> queryUserByIdAndAddr(@Param("ew") QueryWrapper<User> wrapper);

    @Update("UPDATE user SET balance = balance - #{money} WHERE id = #{id}")
    void deductMoneyById(@Param("id") Long id, @Param("money") Integer money);
}
<?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.gina.mapper.UserMapper">
</mapper>

【9】service

public interface IUserService extends IService<User> {

    List<User> queryUserByIdAndAddr(List<Long> ids, String city);

    Boolean deductBalance(Long id, Integer money);

    List<User> queryUserByNameStatusBalance(String name, UserStatus status, Integer minBalance, Integer maxBalance);

    UserVO queryUserAndAddressById(Long userId);

    List<UserVO> queryUserAndAddressByIds(List<Long> ids);

    PageDTO<UserVO> queryUserPage(UserQuery query);
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> queryUserByIdAndAddr(List<Long> ids, String city) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
        queryWrapper.in("user.id", ids)
                    .eq("address.city", city);
        return userMapper.queryUserByIdAndAddr(queryWrapper);
    }

    @Override
    @Transactional
    public Boolean deductBalance(Long id, Integer money) {
        User user = this.getById(id);
        // 2.判断用户状态
        if (user == null || user.getStatus() == UserStatus.FREEZE) {
            return false;
        }
        // 3.判断用户余额
        if (user.getBalance() < money) {
            return false;
        }
        // 4.扣减余额
        Integer remainBalance = user.getBalance() - money;
        this.lambdaUpdate().set(User::getBalance, remainBalance)
                .set(remainBalance == 0, User::getStatus, UserStatus.FREEZE)
                .eq(User::getId, id)
                .eq(User::getBalance, user.getBalance())//乐观锁
                .update();
        return true;
    }

    @Override
    public List<User> queryUserByNameStatusBalance(String name, UserStatus status, Integer minBalance, Integer maxBalance) {
        return this.lambdaQuery()
                .like(name != null, User::getUsername, name)
                .eq(status != null, User::getStatus, status)
                .ge(minBalance != null, User::getBalance, minBalance)
                .le(maxBalance != null, User::getBalance, maxBalance)
                .list();
    }

    @Override
    public UserVO queryUserAndAddressById(Long userId) {
        // 1.查询用户
        User user = getById(userId);
        if (user == null || user.getStatus() == UserStatus.FREEZE) {
            return null;
        }
        // 2.查询收货地址
        List<Address> addresseslist = Db.lambdaQuery(Address.class)
                .eq(Address::getUserId, userId).list();
        // 3.处理vo
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        if (addresseslist != null) {
            userVO.setAddressList(BeanUtil.copyToList(addresseslist, AddressVO.class));
        }
        return userVO;
    }

    @Override
    public List<UserVO> queryUserAndAddressByIds(List<Long> ids) {
        //1查询用户
        List<User> users = listByIds(ids);
        if (users == null) {
            return Collections.emptyList();
        }
        //2 查询地址
        //2.1 查询用户id集合
        List<Long> idsList = users.stream().map(User::getId).collect(Collectors.toList());
        //2.2 根据用户id查地址
        List<Address> addressList = Db.lambdaQuery(Address.class)
                .in(Address::getUserId, idsList)
                .list();
        //2.3 转addVO
        List<AddressVO> addressVOList = BeanUtil.copyToList(addressList, AddressVO.class);
        //2.4 用户地址集合分组,分类整理,相同的用户放到一个集合中
        Map<Long, List<AddressVO>> addressMap = new HashMap<>();
        if (addressVOList != null) {
            addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));
        }
        List<UserVO> userVOList = new ArrayList<>(users.size());
        for (User user : users) {
            UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
            userVO.setAddressList(addressMap.get(user.getId()));
            userVOList.add(userVO);
        }
        return userVOList;
    }

    @Override
    public PageDTO<UserVO> queryUserPage(UserQuery query) {
        // 1.构建条件
        Page<User> page = query.toMpPageDefaultSortByCreateTimeDesc();

        String name = query.getName();
        UserStatus status = query.getStatus();
        //2.查询
        Page<User> queriedPage = lambdaQuery()
                .like(name != null, User::getUsername, name)
                .eq(status != null, User::getStatus, status)
                .gt(query.getMinBalance() != null, User::getBalance, query.getMinBalance())
                .lt(query.getMinBalance() != null, User::getBalance, query.getMaxBalance())
                .page(page);

//        return PageDTO.of(queriedPage,UserVO.class);
        return PageDTO.ofMyself(queriedPage, user -> {
            UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
            userVO.setUsername(userVO.getUsername().substring(0, userVO.getUsername().length() - 2) + "**");
            return userVO;
        });
    }
}
public interface IAddressService extends IService<Address> {
    PageDTO<AddressVO> getaAddressWithProvince(AddressQuery addressQuery);
}

@Service
public class AddressServiceImpl extends ServiceImpl<AddressMapper, Address> implements IAddressService {

    @Autowired
    private IUserService userService;

    @Override
    public PageDTO<AddressVO> getaAddressWithProvince(AddressQuery addressQuery) {
        Page<Address> page = addressQuery.toMpPageDefaultSortByCreateTimeDesc();

        String province = addressQuery.getProvince();
        String city = addressQuery.getCity();
        String town = addressQuery.getTown();

        Page<Address> queriedPage = lambdaQuery()
                .eq(province != null, Address::getProvince, province)
                .eq(city != null, Address::getCity, city)
                .eq(town != null, Address::getTown, town)
                .page(page);

        PageDTO<AddressVO> addressVOPageDTO = PageDTO.of(queriedPage, AddressVO.class);

        List<AddressVO> records = addressVOPageDTO.getList();
        for (int i = 0; i < records.size(); i++) {
            AddressVO add = records.get(i);
            User user = userService.getById(add.getUserId());
            UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
            add.setUserVO(userVO);
            records.set(i, add);
        }
        addressVOPageDTO.setList(records);
        return addressVOPageDTO;
    }
}

【10】MybatisPlus04GeneratorApplication

@SpringBootApplication
public class MybatisPlus04GeneratorApplication {

    public static void main(String[] args) {
        SpringApplication.run(MybatisPlus04GeneratorApplication.class, args);
    }
}

【11】最终访问地址

http://localhost:8080/doc.html#/home

【12】接口管理界面

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值