SpringBoot项目(第二天实现注册)

1、项目技术

开发工具:Idea 
开发框架:SpringBoot(Spring + Spring MVC + MyBatis) 
数据库:  Mysql

2、实现功能

1、实现注册
2、下面只写到了实现网页查看数据是否与数据库连接,页面还没实现,下篇讲解从mapper<service<controller三层查找数据后,如何把数据响应回页面。

3、项目架构

在这里插入图片描述

4、下载地址

5、开始项目

5.1、注册mapper持久层 > service业务层 > controller控制器

第一篇已经创建数据库,成功:
在这里插入图片描述

5.2、注册mapper层 -- 实体类

import lombok.Data;

import java.io.Serializable;
import java.util.Date;
/**
 * 实体类的基类
 */
 @Data
abstract class BaseEntity implements Serializable {

	private static final long serialVersionUID = -3122958702938259476L;
	
	private String createdUser;
	private Date createdTime;
	private String modifiedUser;
	private Date modifiedTime;
	
}
   
import lombok.Data;

/**
 * 用户实体类
 */
@Data
public class User extends BaseEntity{
    private static final long serialVersionUID = -6992489078211958584L;
    private Integer uid;
    private String username;
    private String password;
    private String salt;
    private Integer gender;
    private String phone;
    private String email;
    private String avatar;
    private Integer isDelete;
}

持久层开发

(a)规划需要执行的sql语句
此次需要实现的功能是“注册”,其本质是向数据表中插入新的数据,需要执行的SQL语句大致是:

insert into t_user (除了uid以外的所有字段) values (匹配的值列表);

在执行插入数据之前,还应该检查该用户名是否已经注册过,所以,还需要执行查询操作,其SQL语句大致是:

select * from t_user where username=?

(b) 接口与抽象方法

Integer insert(User user);
User findByUsername(String username);

第一次配置持久层接口,需要给SprigBoot指定持久层接口的位置,在启动类里面添加:
在这里插入图片描述

在**application.properties**文件中添加关于XML映射文件的位置的配置信息:
mybatis.mapper-locations=classpath:mappers/*.xml

(c)、编写UserMapper

import com.example.springbootdemo.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper {

    /**
     * 用户注册,添加用户
     * @param user
     * @return
     */
    Integer insert(User user);

    /**
     * 用户注册,判断用户名是否被占用
     * @param username
     * @return
     */
    User findByUsername(String username);
    
}

(d)、配置映射
在配置映射时,注意:
mapper – namespace对应的是定义的mapper接口

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"
        "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">

<!--  指定mapper接口  -->
<mapper namespace="com.example.springbootdemo.mapper.UserMapper">

    <!--   指定User用户实体类  -->
    <resultMap id="UserEntityMap"
               type="com.example.springbootdemo.entity.User">
        <id column="uid" property="uid"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="salt" property="salt"/>
        <result column="gender" property="gender"/>
        <result column="phone" property="phone"/>
        <result column="email" property="email"/>
        <result column="avatar" property="avatar"/>
        <result column="is_delete" property="isDelete"/>
        <result column="created_user" property="createdUser"/>
        <result column="created_time" property="createdTime"/>
        <result column="modified_user" property="modifiedUser"/>
        <result column="modified_time" property="modifiedTime"/>
    </resultMap>

    <!-- 插入用户数据 -->
    <!-- Integer insert(User user) -->
    <insert id="insert"
            useGeneratedKeys="true"
            keyProperty="uid">
            INSERT INTO t_user (
            username, password,
            salt, gender,
            phone, email,
            avatar, is_delete,
            created_user, created_time,
            modified_user, modified_time
            ) VALUES (
            #{username}, #{password},
            #{salt}, #{gender},
            #{phone}, #{email},
            #{avatar}, #{isDelete},
            #{createdUser}, #{createdTime},
            #{modifiedUser}, #{modifiedTime}
            )
        </insert>

    <!-- 根据用户名查询用户数据详情 -->
    <!-- User findByUsername(String username) -->
    <select id="findByUsername"
            resultMap="UserEntityMap">
            SELECT
            *
            FROM
            t_user
            WHERE
            username=#{username}
        </select>

</mapper>

业务层service层

(a) 规划异常

用户名是否被占用,如果被占用,则抛出异常:
      UsernameDuplicateException异常类;
插入数据时,返回的受影响的行数可能不是1,则插入数据失败,也需要抛出异常:
      InsertException异常类
异常的基类: 
      ServiceException,继承自RuntimeException。

(b) 接口与抽象方法

void register(User user);

© 实现业务
这个时候创建个工具类,因为MD5加密可以放出来,在路径下,新建util包,存放MD5Util

import org.springframework.util.DigestUtils;

/**
 * md5加密工具类
 * 
 * @author Administrator
 * 
 */
public class MD5Util {

	public static String getMd5Password(String password, String salt) {
		// 加密规则:
		// 在密码的左右两侧各拼接一次盐值
		// 执行5次加密
		String str = salt + password + salt;
		for (int i = 0; i < 5; i++) {
			str = DigestUtils
					.md5DigestAsHex(str.getBytes())
					.toUpperCase();
		}
		return str;
	}
}

业务实现

import com.example.springbootdemo.entity.User;
import com.example.springbootdemo.mapper.UserMapper;
import com.example.springbootdemo.service.IUserService;
import com.example.springbootdemo.service.ex.InsertException;
import com.example.springbootdemo.service.ex.UsernameDuplicateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
public class UserServiceImpl implements IUserService {

	    @Autowired
	    private UserMapper userMapper;
	
	    @Override
	    public void register(User user) {
        // 先查询用户输入username
        String username = user.getUsername();
        // 根据用户输入username查找数据库有没有数据
        User user1 = userMapper.findByUsername(username);
        // 当用户输入不为null,说明数据库中存在此用户名!
        if (user1 != null) {
            // 抛出用户名已经占用异常
            throw new UsernameDuplicateException("尝试的用户名" + username + "已经被占用!");
        }
        // 用户名没有被占用
        String salt = UUID.randomUUID().toString().toUpperCase();
        // 基于原密码和盐值进行加密处理
        String md5Password = MD5Util.getMd5Password(user.getPassword(), salt);
        // 补全数据:将盐值、新密码设置到salt、password属性
        user.setSalt(salt);
        user.setPassword(md5Password);
        user.setIsDelete(0);
        user.setCreatedTime(new Date());
        user.setCreatedUser(username);
        user.setModifiedTime(new Date());
        user.setModifiedUser(username);
        user.setEmail(user.getEmail());
        user.setPhone(user.getPhone());
        Integer rows = userMapper.insert(user);
        if (rows != 1) {
            throw new InsertException("添加用户"+username+"未成功!!");
        }
    }
}

这个时候就完成注册的业务层了!!

控制器Controller

(a) 处理异常
当发生异常时,创建JsonResult返回信息给控制器响应结果类型,并声明属性。
这个时候,新的知识点又来了,util工具类,在新建JsonResult.

<T> 什么意思呢?
泛型,<T> T表示返回值是一个泛型,传递啥,就返回啥类型的数据,而单独的T就是表示限制你传递的参数类型,
通过一个泛型的返回方式,获取每一个集合中的第一个数据, 通过返回值<T> T 和T的两种方法实现
@Data
public class JsonResult<T> {

	private Integer state; // 响应状态码
    private String message; // 响应信息
    private T data; // 响应数据

	public JsonResult() {
		super();
	}

	public JsonResult(Integer state) {
		super();
		this.state = state;
	}
}
import com.example.springbootdemo.service.ex.InsertException;
import com.example.springbootdemo.service.ex.ServiceException;
import com.example.springbootdemo.service.ex.UsernameDuplicateException;
import com.example.springbootdemo.util.JsonResult;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

/**
 * 控制器的基类,用于判断异常类型返回State状态码
 */
@ControllerAdvice  // 全局异常捕捉处理
public class BaseController {

    @ExceptionHandler(ServiceException.class)
    public JsonResult<Void> handleException(Throwable ex) {
        JsonResult<Void> jsonResult = new JsonResult<>();
        if (ex instanceof UsernameDuplicateException) {
            jsonResult.setState(2);
        } else if (ex instanceof InsertException) {
            jsonResult.setState(3);
        }
        return jsonResult;
    }
}

注册的Controller:UserController

import com.example.springbootdemo.entity.User;
import com.example.springbootdemo.service.IUserService;
import com.example.springbootdemo.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

    @Autowired
    private IUserService userService;

    @RequestMapping("/reg")
    public JsonResult<Void> register(User user){
        userService.register(user);
        return new JsonResult<>(1,"用户"+user.getUsername()+"注册成功!");
    }
}
浏览器输入:
http://localhost:8080/user/reg?username=json&password=1234&gender=1&phone=13800138001&email=[email protected]

成功注册!
在这里插入图片描述
用户名被占用!!
在这里插入图片描述

注册前端界面

注意事项

持久层需要做的事情:

   1、在启动类添加mapper接口对应的地址
      MapperScan(" ")
   2、在application.properties添加添加关于XML映射文件的位置的配置信息:
      mybatis.mapper-locations=classpath:mappers/*.xml

业务层注意的事情

@Service注解加在service实现层Impl

扩展------SpringBoot项目

自带测试工具
在这里插入图片描述
Spring测试需要test项目前添加@RunWith(SpringRunner.class)

import com.example.springbootdemo.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

    @Autowired(required=true)
    private UserMapper mapper;

    @Test
    public void insert() {
        User user = new User();
        user.setUsername("salt001");
        user.setPassword("1234");
        user.setEmail("2212");
        user.setPhone("23123123132");
        System.err.println(user); // uid=null
        Integer rows = mapper.insert(user);
        System.err.println("rows=" + rows);
        System.err.println(user); // uid=2
    }

    //根据用户名查询用户详情
    @Test
    public void findByUsername() {
        String username = "spring1";
        User user = mapper.findByUsername(username);
        System.err.println(user);
    }
}

报错和解决方法

(a)刚开始做项目爆了一堆错,测试mapper的时候如下:

2020-02-04 17:09:07.284 ERROR 5164 --- [           main] o.s.test.context.TestContextManager   : 
   Caught exception while allowing TestExecutionListener 
 [org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@1d296da]
  to prepare test instance [com.example.springbootdemo.mapper.UserMapperTest@d4df0e]
org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'com.example.springbootdemo.mapper.UserMapperTest':
 Unsatisfied dependency expressed through field 'mapper'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type 'com.example.springbootdemo.mapper.UserMapper' available: 
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: 
{@org.springframework.beans.factory.annotation.Autowired(required=true)}
	

解决办法:
MpperScan(” “)定义接口位置错了,少写一个字母,哎,大家以后也要注意检查

(b)service层错误

我说我加了@Service注解了,怎么报错,之前加在service接口上,后来把@Service加在ServiceImpl实现层
错误没了,大家注意,嘻嘻嘻!好歹我找错时间不是很长。

报错信息:

Unsatisfied dependency expressed through field 'userService'; nested exception is 
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 
'com.example.springbootdemo.service.IUserService' available: 
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: 
{@org.springframework.beans.factory.annotation.Autowired(required=true)}

解决办法:
在service实现层加上@Service注解

所用注解

@Service
service实现层的注解,是把spring容器中的bean进行实例化,也就是等同于new操作,只有实现类是可以进行new实例化的,而接口则不能,所以是加在实现类上的。不信你标注到接口上,会报BeanCreationException的。

@MapperScan 作用:指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类
添加位置:是在Springboot启动类上面添加

@Mapper
作用:在接口类上添加了@Mapper,在编译之后会生成相应的接口实现类 添加位置:接口类上面

@Autowired
自动装配,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作

@RestController
相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面

@Controller
在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面
若返回json等内容到页面,则需要加@ResponseBody注解

@ResponseBody
将java对象转为json格式的数据

@ControllerAdvice == @RestControllerAdvice
是Spring3.2提供的新注解,它是一个Controller增强器,可对controller中被
@RequestMapping注解的方法加一些逻辑处理。最常用的就是异常处理

@RequestMapping
一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

@Data
注解的主要作用是提高代码的简洁,使用这个注解可以省去代码中大量的get()、 set()、 toString()等方法;

@Mapper
标注mapper持久层接口

发布了40 篇原创文章 · 获赞 77 · 访问量 2464

猜你喜欢

转载自blog.csdn.net/weixin_45395031/article/details/104167877