今天是 2019 / 10 / 23 13:32!
首先把流程先说一下:
开发步骤: 持久层 > 业务层 > 控制器 > 前端界面
差点忘了发添加的依赖:pom.xml内容
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.2.0.RELEASE
com.zhang
demo_3
0.0.1-SNAPSHOT
demo_3
Demo project for Spring Boot
1.8
com.fasterxml.jackson.core
jackson-databind
2.9.8
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-tomcat
provided
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.0
mysql
mysql-connector-java
runtime
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.springframework.boot
spring-boot-maven-plugin
// 创建数据库user
CREATE DATABASE user;
USE user;
//创建数据表users
CREATE TABLE `users` (
`id` int(100) NOT NULL AUTO_INCREMENT COMMENT 'id',
`username` char(20) NOT NULL COMMENT '用户名',
`password` char(20) NOT NULL COMMENT '密码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf-8mb4;
数据表创建完成!!
解释:第一行最后的 Shanghai也可以换成 Chongqing。上海、重庆。
mybatis插件需要标明扫描的是哪里的 xml内容。
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf- 8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
mybatis.mapper-locations=classpath:mappers/*.xml
1、先编写实体类,User实体类。为com.zhang.demo_3.entity下新建的User实体类!
package com.zhang.demo_3.entity;
import java.util.Objects;
public class User {
//序列化版本号
private static final long serialVersionUID = 1L;
private Integer id;
private String username;
private String password;
//getter和settte方法、tostring 等方法自己写 !!
}
2、在com.zhang.demo_3 下添加 mapper 包,添加 UserMapper 接口,为com.zhang.demo_3.mapper下的UserMapper接口。
内容如下:
注意:记得在接口前添加 @Mapper注解,用于表明这是持久层接口!
package com.zhang.demo_3.mapper;
import com.zhang.demo_3.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);
/**
* 根据id查找信息
* @param id
* @return
*/
User findById(Integer id);
}
3、在 resource 目录下添加 mappers 包, 编写 UserMapper.xml 文件,
** 这是 resource目录下的com.zhang.demo_3下的mappers **
内容如下:
注意:resultType为使用的具体实体类,还可以使用 resultMap 作为返回值!
INSERT INTO users(
id,username,
password
)VALUES(
#{id},#{username},
#{password}
)
1、在com.zhang.demo_3下新建mapper包,并添加UserMapperTest测试类。
解释:
这是测试mapper包下的 UserMapper接口和 UserMapper.xml是否能连接数据库进行查询 !!
package com.zhang.demo_3.mapper;
import com.zhang.demo_3.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;
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserMapperTest {
@Autowired(required=true)
private UserMapper userMapper;
//测试添加数据
@Test
public void insert(){
User user=new User();
String username="zhangsan";
String password="123456";
Integer id=2;
user.setId(id);
user.setPassword(password);
user.setUsername(username);
Integer rows=userMapper.insert(user);
System.out.println(rows);
}
//测试查找用户名
@Test
public void findByUsername(){
String username="zhangsan";
User result=userMapper.findByUsername(username);
System.out.println(result);
}
//测试根据id查找内容
@Test
public void findById(){
Integer id=4;
User result=userMapper.findById(id);
System.out.println(result);
}
}
这样持久层就完成了 !!开发业务层
(a) 规划异常
ServiceException :异常基类,便于后继处理!
package com.zhang.demo_3.service.ex;
public class ServiceException extends RuntimeException{
public ServiceException() {
}
public ServiceException(String message) {
super(message);
}
public ServiceException(String message, Throwable cause) {
super(message, cause);
}
public ServiceException(Throwable cause) {
super(cause);
}
public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
UsernameDuplicateException:检查用户名是否被占用,占用已注册!
package com.zhang.demo_3.service.ex;
public class UsernameDuplicateException extends ServiceException {
public UsernameDuplicateException() {
}
public UsernameDuplicateException(String message) {
super(message);
}
public UsernameDuplicateException(String message, Throwable cause) {
super(message, cause);
}
public UsernameDuplicateException(Throwable cause) {
super(cause);
}
public UsernameDuplicateException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
UsernameNotFoundException :用户名找不到,不可以登陆 !
package com.zhang.demo_3.service.ex;
public class UsernameNotFoundException extends ServiceException {
public UsernameNotFoundException() {
}
public UsernameNotFoundException(String message) {
super(message);
}
public UsernameNotFoundException(String message, Throwable cause) {
super(message, cause);
}
public UsernameNotFoundException(Throwable cause) {
super(cause);
}
public UsernameNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
PasswordNotException :密码找不到,密码错误 !
package com.zhang.demo_3.service.ex;
public class PasswordNotException extends ServiceException{
public PasswordNotException() {
}
public PasswordNotException(String message) {
super(message);
}
public PasswordNotException(String message, Throwable cause) {
super(message, cause);
}
public PasswordNotException(Throwable cause) {
super(cause);
}
public PasswordNotException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
(b) 接口与抽象方法
1、创建 com.zhang.demo_3.service.IUserService业务层接口,并在接口中添加功能的抽象方法,关于业务层的抽象方法的设计原则:
返回值:仅以操作成功(例如注册成功,登录成功等)为前提来设计返回值;
方法名:自定义;
参数列表:控制器可提供的,通常是用户提交的数据,及Session中的数据;
抛出异常:所有操作失败(登录时用户名不存在,登录时密码错误,注册时用户名被占用等)对应的异常。
基于以上设计原则,此次“注册”的抽象方法应该是:在com.zhang.demo_3下新建service包,IUserService接口
解释:
这是一个业务层接口。
package com.zhang.demo_3.service;
import com.zhang.demo_3.entity.User;
public interface IUserService {
/**
* 用户注册
* @param
* @return
*/
void reg(User user);
/**
* 用户登录
* @param user
* @return
*/
User login(String username, String password);
}
© 实现业务
进行编写业务层实现类,在com.zhang.demo_3.service下新建一个包impl,用于存放业务层实现类。这里新建一个UserServiceImpl实现类!
注意:记得添加@Service注解,在类中声明持久层对象。
package com.zhang.demo_3.service.impl;
import com.zhang.demo_3.entity.User;
import com.zhang.demo_3.mapper.UserMapper;
import com.zhang.demo_3.service.IUserService;
import com.zhang.demo_3.service.ex.UsernameNotFoundException;
import com.zhang.demo_3.service.ex.PasswordNotException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServieImpl implements IUserService {
@Autowired
private UserMapper userMapper;
//用户注册业务逻辑
@Override
public void reg(User user) {
System.out.print(user.getUsername());
System.out.print(user.getPassword());
//判断用户名是否为null
String username = user.getUsername();
User result = userMapper.findByUsername(username);
if(result != null){
throw new UsernameNotFoundException("注册名被占用");
}
String password=user.getPassword();
user.setUsername(username);
user.setPassword(password);
System.out.print(result);
userMapper.insert(user);
}
//用户登录业务逻辑
@Override
public User login(String username, String password) {
User result=userMapper.findByUsername(username);
if(result == null){
throw new UsernameNotFoundException("用户名不存在");
}
if(!password.equals(result.getPassword())){
throw new PasswordNotException("密码错误");
}
User user =new User();
user.setUsername(username);
user.setPassword(password);
return user;
}
}
1、在 test测试下 com.zhang.demo_3下新建service包,然后建立 UserServiceTest测试类,
内容如下:
package com.zhang.demo_3.service;
import com.zhang.demo_3.entity.User;
import com.zhang.demo_3.mapper.UserMapper;
import com.zhang.demo_3.service.ex.ServiceException;
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;
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserServiceTest {
@Autowired
private IUserService userService;
@Test
public void reg(){
User user=new User();
String username="zhang";
String password="123456";
Integer id=3;
user.setId(id);
user.setPassword(password);
user.setUsername(username);
userService.reg(user);
}
@Test
public void login(){
try {
String username="root";
String password ="1234";
User Result=userService.login(username, password);
System.err.println(Result);
} catch (ServiceException e) {
System.err.println(e.getClass().getName());
System.err.println(e.getMessage());
}
}
}
业务层开发完成,进入控制器开发步骤:
(a) 处理异常
先创建cn.tedu.store.util.JsonResult响应结果类型,并在其中声明需要它可以给客户的数据的属性:
package com.zhang.demo_3.util;
public class JsonResult {
private Integer state;
private T data;
private String message;
public JsonResult() {
super();
}
/**
* 返回异常信息
* @param e
*/
public JsonResult(Throwable e){
this.message=e.getMessage();
}
/**
* 返回状态码和data响应数据类型
* @param state
* @param data
*/
public JsonResult(Integer state, T data) {
this.state = state;
this.data = data;
}
public JsonResult(Integer state, String message) {
this.state = state;
this.message = message;
}
public JsonResult(Integer state) {
this.state = state;
}
//getter和setter方法。。。。
}
此次“注册”时,业务层的“注册”功能可能抛出UsernameDuplicateException或InsertException,这2种异常其实也不只是“注册”才会抛出,其它的某些功能也可能抛出同样的异常,SpringMVC框架提供了统一处理异常的机制,在编写控制器中处理请求的代码时,就不必再关注异常的问题,等同于控制器中处理请求时将异常抛出,由SpringMVC框架再去捕获相关异常,并进行处理即可!
可以在控制器中添加一个专门处理异常的方法,关于方法的设计原则:
权限:应该使用public权限;
返回值:使用与处理请求的方法相同的原则;
方法名称:自定义;
参数列表:至少包括1个异常类型的参数,表示将捕获并处理的异常,另外,根据需要,可以添加HttpServletRequest等参数,但是,并不能像处理请求的方法那样随意添加;
必须添加@ExceptionHandler注解。
所以,处理异常的方法的声明大致是:
@ExceptionHandler
public JsonResult handleException(Throwable ex) {
}
在com.zhang.demo_3下添加 controller包,创建com.zhang.demo_3.controller.BaseController,实现Serializable接口,将作为实体类的基类,由于该类不需要直接创建对象,其存在的价值就是被其它实体类继承,所以,应该使用默认权限,且使用abstract进行修饰:
以上方法必须在控制器类中,也只能作用于当前控制器类中处理请求时抛出的异常,为了使得所有控制器类抛出的异常都可以被处理,应该将以上处理异常的代码添加在控制器类的基类BaseController中:
package com.zhang.demo_3.controller;
import com.sun.org.apache.xml.internal.resolver.helpers.PublicId;
import com.zhang.demo_3.service.ex.PasswordNotException;
import com.zhang.demo_3.service.ex.ServiceException;
import com.zhang.demo_3.service.ex.UsernameDuplicateException;
import com.zhang.demo_3.service.ex.UsernameNotFoundException;
import com.zhang.demo_3.util.JsonResult;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
/**
* 控制器基类
*/
public abstract class BaseController {
/**
* 返回成功状态码2000
*/
public static final int SUCCESS=2000;
@ExceptionHandler({ServiceException.class, FileUploadException.class})
public JsonResult handleException(Throwable ex) {
JsonResult jsonResult=new JsonResult<>(ex);
if(ex instanceof UsernameDuplicateException){
//用户名被占用 - 2002
jsonResult.setState(2002);
}else if(ex instanceof UsernameNotFoundException){
//用户名找不到 - 2003
jsonResult.setState(2003);
}else if(ex instanceof PasswordNotException){
//密码错误
jsonResult.setState(2004);
}
//返回响应值
return jsonResult;
}
}
如果不通过基类处理异常,也可以自定义某个类,在类之前添加@ControllerAdvice或@RestControllerAdvice也可以使得整个项目的所有控制器都应用该处理异常的做法!
编写UesrController类,创建com.zhang.demo_3.controller.UserController类。
注意:@RestController 必须写,里边有PostMapping和RequestMapping();
声明@Autowired private IUserService userService;业务层对象
package com.zhang.demo_3.controller;
import com.zhang.demo_3.entity.User;
import com.zhang.demo_3.service.IUserService;
import com.zhang.demo_3.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
@RestController
@RequestMapping("users")
public class UserController extends BaseController{
@Autowired
private IUserService userService;
@PostMapping("reg")
public JsonResult reg(User user) {
userService.reg(user);
return new JsonResult<>(SUCCESS);
}
@RequestMapping("login")
public JsonResult login(String username, String password, HttpSession session){
User data = userService.login(username,password);
session.setAttribute("uid",data.getId());
session.setAttribute("username",data.getUsername());
return new JsonResult<>(SUCCESS,data);
}
}
完成后,可以通过http://localhost:8080/users/reg?username=json&password=1234进行测试注册。
上边我写的@PostMapping,不可以用这个网址测试。
可以改为@RequestMapping,进行测试。
如下:
注册页面
登录页面
主页
zhuce
denglu