springboot网上商城项目(一)
- (一)项目分析
- 1.项目分析
- 2.开发顺序
- 3.前端资源测试
- (二)用户注册
- 1.创建数据库
- 2.实体类编写
- 3.注册(持久层)
- 4.注册(业务层)
- 5.注册(控制层)
- 6.注册前端页面
- 后记
🎁🎁静态资源及sql文件
链接:https://pan.baidu.com/s/1X-yjmQcPD3PqS21x0HplNA?pwd=23gr
提取码:23gr
(一)项目分析
1.项目分析
📝📝项目功能:登录,注册,热销商品,用户管理(密码,个人信息,头像,收货地址),购物车(展示,增加,删除),订单模块
📝📝开发顺序:注册,登录,用户管理,购物车,商品,订单模块
2.开发顺序
模块的开发顺序:
持久层开发:依据前端页面的设置规划相关的SQL语句,以及进行配置
业务层开发:核心功能控制,业务操作以及异常的处理
控制层开发:接收请求,处理响应
前端开发:JS,Query,AJAX这些技术来连接后台
3.前端资源测试
创建一个springboot项目导入前端静态资源 ,检测是否能够正常显示。如果这个过程访问失败,原因是idea对于JS代码的兼容性较差,编写了js代码但是有的时候不能正常去加载,解决办法有以下四种:
1.clear-install:依次点击MavenProject->store->Lifecycle->clean,等待清理项目完毕后点击同目录下的install重新部署
2.idea缓存清理:点击File下的Invalidate Caches/Restart…然后在弹出的窗口中选择Invalidate and Restart,此时就会自动清除缓存并重新启动idea
3.rebuild重新构建:点击工具栏的Build下的Rebuild Project
4.重启电脑
(二)用户注册
1.创建数据库
创建数据库t_user
CREATE TABLE t_user (uid INT AUTO_INCREMENT COMMENT '用户id',username VARCHAR(20) NOT NULL UNIQUE COMMENT '用户名',password CHAR(32) NOT NULL COMMENT '密码',salt CHAR(36) COMMENT '盐值',phone VARCHAR(20) COMMENT '电话号码',email VARCHAR(30) COMMENT '电子邮箱',gender INT COMMENT '性别:0-女,1-男',avatar VARCHAR(50) COMMENT '头像',is_delete INT COMMENT '是否删除:0-未删除,1-已删除',created_user VARCHAR(20) COMMENT '日志-创建人',created_time DATETIME COMMENT '日志-创建时间',modified_user VARCHAR(20) COMMENT '日志-最后修改执行人',modified_time DATETIME COMMENT '日志-最后修改时间',PRIMARY KEY (uid)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
2.实体类编写
创建用户表实体类(因为在用户表的设计中有4个公共字段,所以将这些字段字段提取出来放在一个实体基类baseEntity中)
//基类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class baseEntity implements Serializable {private String createdUser;private Date createdTime;private String modifiedUser;private Date modifiedTime;
实体类User继承baseEntity(实体类User因为要在网络中以流的形式传输,所以需要serialize序列化)
//实体类
@Data
public class User extends baseEntity implements Serializable {
private Integer uid;
private String username;
private String password;
private String salt;
private String phone;
private String email;
private Integer gender;
private String avatar;
private Integer isDelete;
3.注册(持久层)
mapper接口
//用户模块持久层
//@Mapper
public interface UserMapper {//插入用户数据Integer insert(User user);//根据用户名查找用户数据User findByUsername(String username);
}
mapper的xml映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace用于指定当前的映射文件和哪个接口进行映射,需要指定接口的文件路径,路径需要是包的完整路径结构-->
<mapper namespace="com.cy.store.mapper.UserMapper"><resultMap id="UserEntityMap" type="com.cy.store.entity.User"><id column="uid" property="uid"></id><result column="is_delete" property="isDelete"></result><result column="created_user" property="createdUser"></result><result column="created_time" property="createdTime"></result><result column="modified_user" property="modifiedUser"></result><result column="modified_time" property="modifiedTime"></result></resultMap>
<insert id="insert" useGeneratedKeys="true" keyProperty="uid">insert into t_user(username,password,salt,phone,email,gender,avatar,is_delete,created_user,created_time,modified_user,modified_time) values (#{username},#{password},#{salt},#{phone},#{email},#{gender},#{avatar},#{isDelete},#{createdUser},#{createdTime},#{modifiedUser},#{modifiedTime})</insert><select id="findByUsername" resultMap="UserEntityMap">
select * from t_user where username=#{username}</select>
</map
4.注册(业务层)
service层
接受前端从控制器流转过来的数据
结合真实的注册业务来完成功能业务逻辑的调转和流程
异常规划:
比如,用户在进行注册时可能会产生用户名被占用的错误,这时需要抛出一个异常
1.异常不能用RuntimeException,太笼统了,开发者没办法第一时间定位到具体的错误类型上,我们可以定义具体的异常类型来继承这个异常。
2.正常的开发中异常又要分等级,可能是在业务层产生异常,可能是在控制层产生异常,所以可以创建一个业务层异常的基类,起名ServiceException异常,并使其继承RuntimeException异常。
3.后期开发业务层时具体的异常可以再继承业务层的异常ServiceException。
在service包下创建一个ex包再在下创建ServiceException类作为业务层异常的基类
public class ServiceException extends RuntimeException{public ServiceException() {super();}public ServiceException(String message) {super(message);}public ServiceException(String message, Throwable cause) {super(message, cause);}public ServiceException(Throwable cause) {super(cause);}protected ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {super(message, cause, enableSuppression, writableStackTrace);}
}
分别创建查询异常UsernameDuplicatedException 和插入异常的InsertException 类
public class UsernameDuplicatedException extends ServiceException{/**重写ServiceException的所有构造方法*/
}
//数据插入过程中产生异常
public class InsertException extends ServiceException{/**重写ServiceException的所有构造方法*/
}
创建IUserService接口(接口命名的默认规则:I+业务名字+层的名字)
//用户模块业务层接口
public interface IUserService {void reg(User user);
}
service实现serviceimpl类
@Service
public class UserServiceImpl implements IUserService {@Resourceprivate UserMapper userMapper;@Overridepublic void reg(User user) {String username=user.getUsername();
//调用findbyusername判断用户是否被注册User result= userMapper.findByUsername(username);if (result!=null){throw new UsernameDuplicatedException("用户已经存在");}//密码加密 md5加密算法//串(盐值)+password+串 ---md5进行加密 连续加载三次//盐值就是随机字符串
String oldPassword=user.getPassword();String salt= UUID.randomUUID().toString().toUpperCase();//记录盐值 登录进行密码比较user.setSalt(salt);
//将密码和盐值作为一个整体 加密
String md5password=getMd5Password(oldPassword,salt);
//重新加入
user.setPassword(md5password);
//补全数据user.setIsDelete(0);Date date=new Date();user.setCreatedTime(date);user.setModifiedTime(date);user.setCreatedUser(user.getUsername());user.setModifiedUser(user.getModifiedUser());Integer rows=userMapper.insert(user);
if (rows!=1){throw new InsertException("注册异常");
}}
//定义md5算法加密private String getMd5Password(String password,String salt){for (int i=0 ;i<3;i++){password=DigestUtils.md5DigestAsHex((salt+password+salt).getBytes()).toUpperCase();}return password;}
}
5.注册(控制层)
Controller层
请求路径:/users/reg
请求参数:User user
请求类型:POST
响应结果:JsonResult< void >
在controller包下创建BaseController 类作为控制层下类的基类,用来做统一的异常捕获:
public class BaseController {public static final int ok = 200;//请求处理方法,这个方法的返回值就是需要传递给前端数据//自动将异常对象传递给此方法的参数列表上//当前项目中产生了异常,被统一拦截到此方法中,这个方法此时充当的是请求处理方法,方法的返回值直接给前端@ExceptionHandler(ServiceException.class)//用于统一处理抛出异常public JsonResult<Void> handleException(Throwable e) {JsonResult<Void> result = new JsonResult<>(e);if (e instanceof UsernameDuplicatedException) {result.setState(400);result.setMessage("用户名存在");} else if (e instanceof InsertException){result.setState(500);result.setMessage("注册出现异常");}return result;}
}
创建UserController类,依赖于业务层的接口,继承BaseController并重构UserController下的reg方法。
@RestController
@RequestMapping("/users")
public class UserController extends BaseController{@Autowiredprivate IUserService userService;@PostMapping("/reg")public JsonResult<Void> reg(@RequestBody User user){userService.reg(user);return new JsonResult<>(ok);}
}
6.注册前端页面
ajax函数:
这是jQuery封装的一个函数,称为$.ajax()函数,通过对象调用ajax()函数用来异步加载相关的请求.依靠的是JavaScript提供的一个对象:XHR(全称XmlHttpResponse)
ajax()函数的语法结构:
使用ajax()时需要传递一个方法体作为方法的参数来使用(一对大括号就是一个方法体)
ajax接受多个参数时,参数与参数之间使用",“分割
每一组参数之间使用”:"进行分割
参数的组成部分一个是参数的名称(不能随便定义),另一个是参数的值(必须用字符串来表示)
参数的声明顺序没有要求
语法结构:
$.ajax({url: "",type: "",data: "",dataType: "",success: function() {},error: function() {}
});
前端js代码
<script>//1.监听注册按钮是否被点击,如果被点击可以执行一个方法(这里不能像ajax函数那样删去function()只留下{},这是官方规定的!)$("#btn-reg").click(function () {//let username = $("#username").val();//let pwd = $("#password").val();//上面这两行是动态获取表单中控件的数据,但是如果这样获取的话ajax函数中//就是data: "username="+username + "&password="+pwd,但太麻烦了,如// 果这个表单提交的是用户的兴趣爱好,那数据就很多了,一个表单20个数据都很正// 常,如果此时还用这种方式就太麻烦了,所以不建议用这种方式//2.发送ajax()的异步请求来完成用户的注册功能$.ajax({url: "/users/reg",type: "POST",//serialize这个API会自动检测该表单有什么控件,每个控件检测后还会获取每个控// 件的值,拿到这个值后并自动拼接成形如username=Tom&password=123的结构data: $("#form-reg").serialize(),dataType: "JSON",success: function (json) { //1.js是弱数据类型,这个地方不用声明json的数据类型//2.如果服务器成功响应就会将返回的数据传给形参,比如{state: 4000,message: "用户名// 已经被占用",data: null}if (json.state == 200) {alert("注册成功")} else {alert("注册失败")}},error: function (xhr) { //如果问题不在可控范围内,服务器就不会返回自己定//义的json字符串:{state: 4000,message: "用户名已经被占用",data: null}//而是返回一个XHR类型的对象,该对象也有一个状态码名字是statusalert("注册时产生未知的错误!"+xhr.status);}});});</script>
浏览器上输入http://localhost:8080/web/register.html 测试注册功能是否可以注册。此时可能会出现点击注册提交表单时没有任何响应,原因是idea对于JS代码的兼容性较差,编写了js代码但是有的时候不能正常去加载,解决办法有四种,同前面的:项目环境搭建->项目测试->测试静态资源能否正常加载
后记
👉👉💕💕美好的一天,到此结束,下次继续努力!,写作不易,感谢大家的支持!! 🌹🌹🌹