Java Spring Boot Controller、Service、DAO实践

690 阅读3分钟

如果你用过 Spring MVC,那就对 Controller、Service、DAO 三者的概念一定不陌生,我们通过 Controller 来接收请求和返回响应,具体的业务处理则放在 Service层 处理,而 DAO 则实现具体与数据库等持久层的操作。

今天从分层的角度来学习下在 Spring Boot 中的简单应用,业务场景也很简单,就是实现 用户信息 的增删改查,本文重在 这三者 的应用,涉及到更好设计的功能这里不讨论。

本人水平有限,主要针对新手学习用,如有不足,请大佬忽略或轻喷。

依赖

新建个 Spring Boot 项目,添加下面的依赖:

<!--  mysql driver      -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.1.0</version>
</dependency>
<!-- mp依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.5</version>
</dependency>
<!--   @Data     -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.30</version>
</dependency>
<!--  params validate -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

主要目录

目录结构如下图所示:

image.png

配置文件

application.yml内容:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://{ip}:3306/mybatis_demo?&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true

后面的实现从 DAO -> Service -> Controller 依次实现。

DAO(Mapper)

新建个 UserInfoMapper.java

package com.example.springbootmybatisplusdemo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.springbootmybatisplusdemo.entity.UserInfo;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}

Service

实现简单的功能:

package com.example.springbootmybatisplusdemo.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.springbootmybatisplusdemo.entity.UserInfo;
import com.example.springbootmybatisplusdemo.mapper.UserInfoMapper;
import com.example.springbootmybatisplusdemo.utils.CryptoUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserInfoServiceImpl implements UserInfoService<UserInfo> {

    @Autowired
    private UserInfoMapper userInfoMapper;

    private static final String salt = "crypto";

    public UserInfoServiceImpl() {
        super();
    }

    @Override
    public boolean createUserInfo(UserInfo userInfo) {
        // check if exist repeated user
        QueryWrapper qw = new QueryWrapper<>();
        qw.eq("phone", userInfo.getPhone());
        Long count = userInfoMapper.selectCount(qw);
        if (count > 0) return false;

        // crypto password
        String pwd = userInfo.getPassword() + salt;
        userInfo.setPassword(CryptoUtils.md5Sum(pwd));

        // insert into database
        int affected = userInfoMapper.insert(userInfo);
        if (affected != 1) return false;

        return true;
    }

    @Override
    public boolean deleteUserInfo(Long id) {
        // logic delete
        int affected = userInfoMapper.deleteById(id);
        if (affected != 1) return false;

        return true;
    }

    @Override
    public UserInfo getUserInfo(Long id) {
        // query user info by userId
        UserInfo user = userInfoMapper.selectById(id);
        return user;
    }

    @Override
    public boolean updateUserInfo(UserInfo userInfo) {
        // update table set ...
        int affected = userInfoMapper.updateById(userInfo);
        if (affected != 1) return false;

        return true;
    }
}

Controller

实现几个接口:

package com.example.springbootmybatisplusdemo.controller;

import com.example.springbootmybatisplusdemo.entity.UserInfo;
import com.example.springbootmybatisplusdemo.service.UserInfoServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/user")
public class UserManagerController {

    @Autowired
    UserInfoServiceImpl userInfoService;

    @PostMapping("/register")
    public Object register(@RequestBody UserInfo userInfo) {
        boolean result = userInfoService.createUserInfo(userInfo);
        Map<String, Object> data = new HashMap<>();
        data.put("result", result);
        return data;
    }

    @DeleteMapping("/deregister/{id}")
    public Object deregister(@PathVariable("id") Long id) {
        boolean result = userInfoService.deleteUserInfo(id);
        Map<String, Object> data = new HashMap<>();
        data.put("result", result);
        return data;
    }

    @GetMapping("/info/{id}")
    public UserInfo getInfo(@PathVariable("id") Long id) {
        UserInfo user = userInfoService.getUserInfo(id);
        return user;
    }

    @PostMapping("/update/")
    public Object updateInfo(@RequestBody UserInfo userInfo) {
        userInfoService.updateUserInfo(userInfo);
        return null;
    }
}

最后在 启动入口处 加上注解:

package com.example.springbootmybatisplusdemo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan(basePackages = "com.example.springbootmybatisplusdemo.mapper")
public class SpringbootMybatisPlusDemoApplication {

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

}

p.s. UserInfo用户bean

package com.example.springbootmybatisplusdemo.entity;

import com.baomidou.mybatisplus.annotation.*;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;

import java.time.LocalDateTime;

@Data
@TableName(value = "user_info")
public class UserInfo {
    @TableId(type = IdType.AUTO)
    private Long id;

    @NotBlank
    @NotNull
    @Size(min = 4, max = 30, message = "name's length is too long or to short.")
    private String name;

    @Size(min = 8, max = 20)
    private String password;

    private String address;

    @Size(min = 11, max = 11, message = "phone's length should be 11.")
    private String phone;

    @TableField(fill = FieldFill.INSERT, value = "created_time")
    private LocalDateTime createdTime;

    @TableField(fill = FieldFill.UPDATE, value = "updated_time")
    private LocalDateTime updatedTime;

    @TableLogic(value = "false", delval = "true")
    @TableField(value = "is_deleted")
    private boolean isDeleted;
}

工具类:

package com.example.springbootmybatisplusdemo.utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class CryptoUtils {
    public static final String ALGO = "MD5";

    public static String md5Sum(String val) {
        if (val == null) val = "";

        String str = "";
        try {
            MessageDigest msgD = MessageDigest.getInstance(ALGO);
            msgD.update(val.getBytes());
            byte[] bytes = msgD.digest();

            int i;
            StringBuilder builder = new StringBuilder();
            for (int j = 0; j < bytes.length; j++) {
                i = bytes[j];
                if (i < 0) i += 256;
                if (i < 16) builder.append("0");

                builder.append(Integer.toHexString(i));
            }

            str = builder.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        return str;
    }

    public static void main(String[] args) {
        System.out.println(CryptoUtils.md5Sum("Hello world!" + "crypto"));
    }
}

创建表的 SQL 语句:

CREATE TABLE `user_info` (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(30) NOT NULL,
    password CHAR(32) NOT NULL,
    address varchar(50) DEFAULT '',
    phone CHAR(11) NOT NULL UNIQUE KEY,
    created_time DATETIME NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间',
    updated_time DATETIME NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改时间',
    is_deleted BOOLEAN
) ENGINE =innodb, CHARSET =utf8;