一.需求
1.OVLS数据库结构
2.OVLS采用技术
后端:SpringMVC、SpringBoot、SpringCloud、MyBatis、Restful、Redis、MySQL等
前端:jquery、ajax、bootstrap、jquery插件
3.架构思想:
前后分离模式(Vue+Ajax、jQuery+Ajax)
后端采用restful服务模式-restful服务架构
微服务架构(SpringBoot+SpringCloud)
系统缓存(redis)
静态资源服务器(Nginx)
流媒体服务器(red5,rtmp|rtmpt)
SpringCloud服务管理(注册、查找、调用、集群、容错、网关等)
...支付功能、集群
二.项目创建(准备工作三件事)
创建一个maven Project项目,取名为ovls-user
-
pom.xml导入jar包
-
添加application.properties
-
添加启动类
1.导包:
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.xdl</groupId>
<artifactId>ovls-user</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
</dependencies>
</project>
2.添加配置文件(用户服务7001)
在src/main/resources里面添加appliction.properties
#设置访问端口
server port=7001
#连接数据库
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/ovls?userUnicode=true&characterEncoding=utf8
spring.datasource.driverClassName=com.mysql.jdbc.Driver
#连接redis
#spring.redis.host=localhost
#spring.redis.port=6379
3.创建启动类
在src/main/java创建一个cn.xdl.ovls包,再创建UserRunBoot类
package cn.xdl.ovls;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication//启动程序
public class UserRunBoot {
public static void main(String[] args) {
SpringApplication.run(UserRunBoot.class, args);
}
}
三.restful服务(注册)
1.注册服务
发送post请求:/user/regist post
流程:
/user/regist–>
UserController–>
UserService–>
UserMapper–>
返回JSON结果
2.创建包名
控制器cn.xdl.ovls.controller
接口cn.xdl.ovls.dao
实体cn.xdl.ovls.entity
服务cn.xdl.ovls.service
一.user.dao接口DAO
1.从MyBatis Generator工具拿出创建的实体类User并序列化User
package cn.xdl.ovls.entity;
import java.io.Serializable;
import java.util.Date;
//序列化
public class User implements Serializable{
/**
* ID编号(主键)
*/
private Integer id;
/**
* 账号
*/
private String name;
/**
* 密码
*/
private String password;
/**
* 昵称
*/
private String nickName;
/**
* 职位
*/
private String position;
/**
* 性别
*/
private String sex;
/**
* 所在地
*/
private String location;
/**
* 个性签名
*/
private String signature;
/**
* 头像路径
*/
private String image;
/**
* 注册时间
*/
private Date regtime;
/**
*密码加盐
*/
private String salt;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name == null ? null : name.trim();
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password == null ? null : password.trim();
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName == null ? null : nickName.trim();
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position == null ? null : position.trim();
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex == null ? null : sex.trim();
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location == null ? null : location.trim();
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature == null ? null : signature.trim();
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image == null ? null : image.trim();
}
public Date getRegtime() {
return regtime;
}
public void setRegtime(Date regtime) {
this.regtime = regtime;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt == null ? null : salt.trim();
}
}
2.从MyBatis Generator工具拿出创建的DAO接口和实现类UserMapper接口和UserSqlProvider实现类
3.在启动类添加映射扫描器
@MapperScan(basePackages={"cn.xdl.ovls.dao"})
4.添加dao测试类TestUserMapper
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;
import cn.xdl.ovls.UserRunBoot;
import cn.xdl.ovls.dao.UserMapper;
import cn.xdl.ovls.entity.User;
//在测试开始的时候自动创建Spring的应用上下文
@RunWith(SpringRunner.class)
//容器实例化,跟着UserRunBoot.class启动
@SpringBootTest(classes={UserRunBoot.class})
public class TestUserMapper {
@Autowired//注入UserMapper
private UserMapper userDao;
/**
* 测试环境查询数据库中数据检测是否连接正常
*/
@Test
public void test1(){
//查询selectByPrimaryKey
User user = userDao.selectByPrimaryKey(1);
if(user != null){
//有输出用户名和密码
System.out.println(user.getName()+" "+user.getPassword() );
}else{
//无输出差无此人
System.out.println("查无此人");
}
}
}
测试结果
二.服务service
1.UserMapper.java先在dao包的UserMapper接口里面
package cn.xdl.ovls.dao;
import cn.xdl.ovls.entity.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.UpdateProvider;
import org.apache.ibatis.type.JdbcType;
public interface UserMapper {
/**
*/
@Delete({
"delete from user",
"where id = #{id,jdbcType=INTEGER}"
})
int deleteByPrimaryKey(Integer id);
/**
* 添加
*/
@Insert({
"insert into user (id, name, ",
"password, nick_name, ",
"position, sex, location, ",
"signature, image, ",
"regtime, salt)",
"values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, ",
"#{password,jdbcType=VARCHAR}, #{nickName,jdbcType=VARCHAR}, ",
"#{position,jdbcType=VARCHAR}, #{sex,jdbcType=VARCHAR}, #{location,jdbcType=VARCHAR}, ",
"#{signature,jdbcType=VARCHAR}, #{image,jdbcType=VARCHAR}, ",
"#{regtime,jdbcType=TIMESTAMP}, #{salt,jdbcType=VARCHAR})"
})
int insert(User record);
/**
* 按照字段添加
*/
@InsertProvider(type=UserSqlProvider.class,method="insertSelective")
int insertSelective(User record);
/**
*/
@Select({
"select",
"id, name, password, nick_name, position, sex, location, signature, image, regtime, ",
"salt",
"from user",
"where id = #{id,jdbcType=INTEGER}"
})
@Results({
@Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
@Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
@Result(column="password", property="password", jdbcType=JdbcType.VARCHAR),
@Result(column="nick_name", property="nickName", jdbcType=JdbcType.VARCHAR),
@Result(column="position", property="position", jdbcType=JdbcType.VARCHAR),
@Result(column="sex", property="sex", jdbcType=JdbcType.VARCHAR),
@Result(column="location", property="location", jdbcType=JdbcType.VARCHAR),
@Result(column="signature", property="signature", jdbcType=JdbcType.VARCHAR),
@Result(column="image", property="image", jdbcType=JdbcType.VARCHAR),
@Result(column="regtime", property="regtime", jdbcType=JdbcType.TIMESTAMP),
@Result(column="salt", property="salt", jdbcType=JdbcType.VARCHAR)
})
User selectByPrimaryKey(Integer id);
/**
* 插入在这里判断用户是否存在 根据用户名查询
*/
/**
*/
@UpdateProvider(type=UserSqlProvider.class,method="updateByPrimaryKeySelective")
int updateByPrimaryKeySelective(User record);
/**
*/
@Update({
"update user",
"set name = #{name,jdbcType=VARCHAR},",
"password = #{password,jdbcType=VARCHAR},",
"nick_name = #{nickName,jdbcType=VARCHAR},",
"position = #{position,jdbcType=VARCHAR},",
"sex = #{sex,jdbcType=VARCHAR},",
"location = #{location,jdbcType=VARCHAR},",
"signature = #{signature,jdbcType=VARCHAR},",
"image = #{image,jdbcType=VARCHAR},",
"regtime = #{regtime,jdbcType=TIMESTAMP},",
"salt = #{salt,jdbcType=VARCHAR}",
"where id = #{id,jdbcType=INTEGER}"
})
int updateByPrimaryKey(User record);
}
添加以下方法
/**
*判断用户是否存在 根据用户名查询
*/
@Select({
"select",
"id, name, password, nick_name, position, sex, location, signature, image, regtime, ",
"salt",
"from user",
"where name = #{name,jdbcType=VARCHAR}"
})
@Results({
@Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
@Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
@Result(column="password", property="password", jdbcType=JdbcType.VARCHAR),
@Result(column="nick_name", property="nickName", jdbcType=JdbcType.VARCHAR),
@Result(column="position", property="position", jdbcType=JdbcType.VARCHAR),
@Result(column="sex", property="sex", jdbcType=JdbcType.VARCHAR),
@Result(column="location", property="location", jdbcType=JdbcType.VARCHAR),
@Result(column="signature", property="signature", jdbcType=JdbcType.VARCHAR),
@Result(column="image", property="image", jdbcType=JdbcType.VARCHAR),
@Result(column="regtime", property="regtime", jdbcType=JdbcType.TIMESTAMP),
@Result(column="salt", property="salt", jdbcType=JdbcType.VARCHAR)
})
User selectByName(String name);
2.编写服务service
package cn.xdl.ovls.service;
import cn.xdl.ovls.util.OvlsResult;
/**
* 需求文档:用户管理:登录.注册.修改密码.修改个人信息.登录检查功能
*/
public interface UserStrvice {
/**
* 一.注册
*/
public OvlsResult addUser(String name,String password);
}
3.设定约定方法状态码常量(增加状态码可读性)
在cn.xdl.ovls.util包中增加OvlsConstant类
package cn.xdl.ovls.util;
public class OvlsConstant {
public static final int SUCCESS = 0; //成功
public static final int ERROR = -1; //异常
public static final int ERROR1 = 1; //失败1
public static final int ERROR2 = 2; //失败2
public static final int ERROR3 = 3; //失败3
public static final String SUCCESS_MSG = "操作成功";
public static final String ERROR_MSG = "操作异常";
public static final String REGIST_ERROR1_MSG = "用户名被占用";
public static final String LOGIN_ERROR1_MSG = "用户名不存在";
public static final String LOGIN_ERROR2_MSG = "用户密码不正确";
}
三.实现类UserServiceImpl继承UserStrvice
package cn.xdl.ovls.service;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.xdl.ovls.dao.UserMapper;
import cn.xdl.ovls.entity.User;
import cn.xdl.ovls.util.OvlsConstant;
import cn.xdl.ovls.util.OvlsResult;
import cn.xdl.ovls.util.PasswordUtil;
import net.bytebuddy.asm.Advice.Return;
@Service//扫描
public class UserServiceImpl implements UserStrvice {
@Autowired//通过UserMapper注入
private UserMapper userDao;
/**
* 一.2注册
* 插入语句:无返回值,只有两种情况1.成功2.抛异常
*/
public OvlsResult addUser(String name, String password) {
//构建一个result
OvlsResult result = new OvlsResult();
//判断用户名是否存在
User user = userDao.selectByName(name);
if(user != null){
//setStatus设置状态
result.setStatus(OvlsConstant.ERROR1);
//setMsg设置状态信息
result.setMsg(OvlsConstant.REGIST_ERROR1_MSG);
//输出返回值
return result;
}
//添加用户
user = new User();
user.setName(name);
//TODO 密码加密处理
String salt = PasswordUtil.salt();
//通MD5加密处理
String md5Pwd = PasswordUtil.md5(password+salt);
//设置加密密码
user.setPassword(md5Pwd);
//设置盐值
user.setSalt(salt);
user.setRegtime(new Date());//注册时间.系统当前时间
userDao.insertSelective(user);
result.setStatus(OvlsConstant.SUCCESS);
result.setMsg(OvlsConstant.SUCCESS_MSG);
return result;
}
}
四.局部异常处理(出异常全部走这里)
package cn.xdl.ovls.controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.xdl.ovls.util.OvlsResult;
@ControllerAdvice
public class MyErrorController {
/**
* @ExceptionHandler处理Controller抛出的异常
* @ResponseBody用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区
* handlerException处理器异常解析器
* setStatus设置状态
* setMsg设置状态信息
*/
@ExceptionHandler
@ResponseBody
public Object handlerException(Exception ex){
OvlsResult result = new OvlsResult();
result.setStatus(-1);
result.setMsg("系统异常");
return result;
}
}
五.接口UserController
作用是接收请求和接收参数
返回结果多的话可以自定义返回值代表什么
1.先添加一个实体类OvlsResult在cn.xdl.ovls.util包里
package cn.xdl.ovls.util;
public class OvlsResult {
//定义状态及状态信息
private int status;
private String msg;
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
2.注册接口UserController
package cn.xdl.ovls.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.xdl.ovls.service.UserStrvice;
import cn.xdl.ovls.util.OvlsConstant;
import cn.xdl.ovls.util.OvlsResult;
@RestController//处理返回的数据格式,使用了该类型注解后,该类下的所有方法都会返回json数据格式不再是视图,不会进行转跳
public class UserController {
@Autowired//通过UserMapper注入
private UserStrvice userService;
/**
* 一.1注册用户
*/
@PostMapping("user/regist")
public OvlsResult result(String name,String password){
//构建一个对象,返回结果
OvlsResult result = userService.addUser(name,password);
return result;
}
/**
* 异常处理
*/
@ExceptionHandler
public Object handlerException(Exception ex){
OvlsResult result = new OvlsResult();
result.setStatus(OvlsConstant.ERROR);
result.setMsg(OvlsConstant.ERROR_MSG);
return result;
}
}
测试注册结果先启动UserRunBoot服务
注册成功
用户被占用
二.登录功能
流程
设计需求:/user/login POST请求 用户.密码
设计流程:
/user/login–>
UserController–>
UserService–>
UserMapper–>
返回JSON结果
一.接口UserService里面添加登录
/**
* 二.登录
*/
public OvlsResult checkUser(String name,String password);
}
二.实现类UserServiceImpl里面添加登录
/**
* 二.登录
* 更新和删除语句:有返回值(顺利执行返回0,要么顺利执行返回1或多,抛异常)
*/
public OvlsResult checkUser(String name,String password){
OvlsResult result = new OvlsResult();
//2.1先根据用户名查询,用户名不存在
User user = userDao.selectByName(name);
if(user == null){
result.setStatus(OvlsConstant.ERROR1);
result.setMsg(OvlsConstant.LOGIN_ERROR1_MSG);
return result;
}
//2.2如果用户存在,对比密码,密码不正确
//user的密码是数据库的加密处理的密码,创建这个密码时拿到Salt后再md5
String md5Pwd = PasswordUtil.md5((password+user.getSalt()));
if(!md5Pwd.equals(user.getPassword())){
result.setStatus(OvlsConstant.ERROR2);
result.setMsg(OvlsConstant.LOGIN_ERROR2_MSG);
return result;
}
//2.3用户名和密码正确
result.setStatus(OvlsConstant.SUCCESS);
result.setMsg(OvlsConstant.SUCCESS_MSG);
return result;
}
三.控制器UserController里添加登录
/**
* 二.登录
* 查询这里涉及到密码用get不安全,所以用post安全
*/
@PostMapping("/user/login")
public OvlsResult login(String name,String password){
OvlsResult result = userService.checkUser(name,password);
return result;
}
四.单体测试类TestUserLogin(正常,无数据,错误)
import org.junit.Assert;
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;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.xdl.ovls.UserRunBoot;
import cn.xdl.ovls.controller.UserController;
import cn.xdl.ovls.util.OvlsConstant;
import cn.xdl.ovls.util.OvlsResult;
@RunWith(SpringRunner.class)
@SpringBootTest(classes={UserRunBoot.class})
public class TestUserLogin {
@Autowired
private UserController controller;
/**
* 一.测试正确结果
*/
@Test
public void test1() throws Exception{
MockMvc mock = MockMvcBuilders.standaloneSetup(controller).build();
RequestBuilder registRequest =
MockMvcRequestBuilders.post("/user/login")
.param("name", "xdl02")
.param("password", "123456");
MvcResult result = mock.perform(registRequest).andReturn();
System.out.println(result.getResponse().getStatus());
String str = result.getResponse().getContentAsString();
System.out.println(str);
//将返回的json字符串转成Ovlsresult对象,进行断言比对
ObjectMapper mapper = new ObjectMapper();
OvlsResult ovlsResult = mapper.readValue(str, OvlsResult.class);
Assert.assertEquals(OvlsConstant.SUCCESS, ovlsResult.getStatus());
}
/**
* 二.测试查询用户名不存在
*/
@Test
public void test2() throws Exception{
MockMvc mock = MockMvcBuilders.standaloneSetup(controller).build();
RequestBuilder registRequest =
MockMvcRequestBuilders.post("/user/login")
.param("name", "xdl03")
.param("password", "123456");
MvcResult result = mock.perform(registRequest).andReturn();
System.out.println(result.getResponse().getStatus());
String str = result.getResponse().getContentAsString();
System.out.println(str);
//将返回的json字符串转成Ovlsresult对象,进行断言比对
ObjectMapper mapper = new ObjectMapper();
OvlsResult ovlsResult = mapper.readValue(str, OvlsResult.class);
Assert.assertEquals(OvlsConstant.ERROR1, ovlsResult.getStatus());
}
/**
* 三.测试密码错误结果
*/
@Test
public void test3() throws Exception{
MockMvc mock = MockMvcBuilders.standaloneSetup(controller).build();
RequestBuilder registRequest =
MockMvcRequestBuilders.post("/user/login")
.param("name", "xdl02")
.param("password", "1234567");
MvcResult result = mock.perform(registRequest).andReturn();
System.out.println(result.getResponse().getStatus());
String str = result.getResponse().getContentAsString();
System.out.println(str);
//将返回的json字符串转成Ovlsresult对象,进行断言比对
ObjectMapper mapper = new ObjectMapper();
OvlsResult ovlsResult = mapper.readValue(str, OvlsResult.class);
Assert.assertEquals(OvlsConstant.ERROR2, ovlsResult.getStatus());
}
}
测试登录结果先启动UserRunBoot服务
1.登录成功
2.用户名不存在
3.密码错误