SpringBoot 您所在的位置:网站首页 php修改已登录的个人信息在哪里 SpringBoot

SpringBoot

2023-12-24 06:40| 来源: 网络整理| 查看: 265

1. 项目分析

在设计一款软件时,在编写代码之前,应该先分析这个项目中需要处理哪些类型的数据!例如,本项目中需要处理的数据种类有:收藏,购物车,用户,收货地址,订单,商品,商品类别。

当确定了需要处理的数据的种类之后,就应该确定这些数据的处理先后顺序:用户 > 收货地址 > 商品类别 > 商品 > 收藏 > 购物车 > 订单。

在具体开发某个数据的管理功能之前,还应该分析该数据需要开发哪些管理功能,以用户数据为例,需要开发的有:修改密码,上传头像,修改资料,登录,注册。

分析出功能之后,也需要确定这些功能的开发顺序,一般先开发简单的,也依据增、查、删、改的顺序,则以上功能的开发顺序应该是:注册 > 登录 > 修改密码 > 修改资料 > 上传头像。

在开发某个数据的任何功能之前,还应该先创建这种数据对应的数据表,然后,创建对应的实体类,再开发某个功能!

在开发某个功能时,还应该遵循顺序:持久层(数据库编程) > 业务层 > 控制器层 > 前端页面。

2. 用户-创建数据表

先创建数据库:

CREATE DATABASE db_store; USE db_store;

然后,在数据库中创建数据表:

CREATE TABLE t_user ( uid INT AUTO_INCREMENT COMMENT '用户id', username VARCHAR(20) UNIQUE NOT NULL COMMENT '用户名', password CHAR(32) NOT NULL COMMENT '密码', salt CHAR(36) COMMENT '盐值', gender INT(1) COMMENT '性别:0-女,1-男', phone VARCHAR(20) COMMENT '手机号码', email VARCHAR(50) COMMENT '电子邮箱', avatar VARCHAR(100) COMMENT '头像', is_delete INT(1) COMMENT '是否删除:0-否,1-是', created_user VARCHAR(20) COMMENT '创建人', created_time DATETIME COMMENT '创建时间', modified_user VARCHAR(20) COMMENT '最后修改人', modified_time DATETIME COMMENT '最后修改时间', PRIMARY KEY (uid) ) DEFAULT CHARSET=utf8mb4;

完成后,可以通过desc t_user;和show create table t_user;进行查看。

3. 用户-创建实体类

创建SpringBoot项目,所以,先打开https://start.spring.io创建项目,创建时,使用的版本选择2.1.12,Group为cn.demo,Artifact为store,Packaging为war,添加Mybatis Framework和MySQL Driver` 依赖,在网站生成项目后,将解压得到的项目文件夹剪切到Workspace中,并在Eclipse中导入该项目。

在src/main/java下,在现有的cn.demo.store包中,创建子级entity包,用于存放实体类,先在entity包中创建所有实体类的基类:

/** * 实体类的基类 */ abstract class BaseEntity implements Serializable { private static final long serialVersionUID = -3122958702938259476L; private String createdUser; private Date createdTime; private String modifiedUser; private Date modifiedTime; // 自行添加SET/GET方法,toString() }

并在entity包中创建User类,继承自以上基类:

/** * 用户数据的实体类 */ public class User extends BaseEntity { private static final long serialVersionUID = -3302907460554699349L; 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; // 自行添加SET/GET方法,基于uid的equals()和hashCode()方法,toString()方法 } 4. 用户-注册-持久层

持久层:持久化保存数据的层。

刚创建好的SpringBoot项目,由于添加了数据库相关的依赖,在没有配置数据库连接信息之前,将无法启动!所以,应该先在application.properties中添加配置:

server.port=8080 spring.datasource.url=jdbc:mysql://localhost:3306/db_store?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=123456 mybatis.mapper-locations=classpath:mappers/*.xml

然后,在cn.demo.store包中,创建mapper子级包,用于存放使用MyBatis编程时的接口文件,并在mapper包中创建UserMapper接口,在接口中添加抽象方法:

/** * 处理用户数据的持久层接口 */ public interface UserMapper { /** * 插入用户数据 * @param user 用户数据 * @return 受影响的行数 */ Integer insert(User user); /** * 根据用户名查询用户数据 * @param username 用户名 * @return 匹配的用户数据,如果没有匹配的数据,则返回null */ User findByUsername(String username); }

然后,需要在启动类的声明之前补充@MapperScan注解,以配置接口文件的位置:

@SpringBootApplication @MapperScan("cn.demo.store.mapper") public class StoreApplication { public static void main(String[] args) { SpringApplication.run(StoreApplication.class, args); } }

在src/main/resources下创建mappers文件夹,该文件夹的名称应该与复制的配置信息中保持一致!并在该文件夹中创建UserMapper.xml文件,以配置2个抽象方法的SQL映射:

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} ) SELECT * FROM t_user WHERE username=#{username}

在src/test/java中的cn.demo.store包中创建子级的mapper包,并在mapper包中创建UserMapperTests测试类,并在测试类的声明之前添加@RunWith(SpringRunner.class)和@SpringBootTest注解:

@RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTests { }

如果使用的是SpringBoot 2.2.x系列的版本,只需要添加1个注解即可,具体使用什么样的注解,请参考默认就存在那个单元测试类。

然后,在单元测试类中编写并执行单元测试:

@RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTests { @Autowired private UserMapper mapper; @Test public void insert() { User user = new User(); user.setUsername("project"); user.setPassword("1234"); user.setSalt("salt"); user.setGender(0); user.setPhone("13800138002"); user.setEmail("[email protected]"); user.setAvatar("avatar"); user.setIsDelete(0); user.setCreatedUser("系统管理员"); user.setCreatedTime(new Date()); user.setModifiedUser("超级管理员"); user.setModifiedTime(new Date()); Integer rows = mapper.insert(user); System.err.println("rows=" + rows); System.err.println(user); } @Test public void findByUsername() { String username = "project"; User result = mapper.findByUsername(username); System.err.println(result); } } 5. 用户-注册-业务层

业务,在普通用户眼里就是“1个功能”,例如“注册”就是一个业务,在开发人员看来,它可能是由多个数据操作所组成的,例如“注册”就至少由“查询用户名对应的用户数据”和“插入用户数据”这2个数据操作组成,多个数据操作组成1个业务,在组织过程中,可能涉及一些相关的检查,及数据安全、数据完整性的保障,所以,业务层的代码主要是组织业务流程,设计业务逻辑,以保障数据的完整性和安全性。

在开发领域中,数据安全指的是:数据是由开发人员所设定的规则而产生或发生变化的!

在业务层的开发中,应该先创建业务层的接口,因为,在实际项目开发中,强烈推荐“使用接口编程”的效果!

所以,先在cn.demo.store包中创建service子包,并在service包中创建UserService业务接口,并在接口中声明“注册”这个业务的抽象方法:

/** * 处理用户数据的业务接口 */ public interface UserService { /** * 用户注册 * @param user 客户端提交的用户数据 */ void reg(User user); }

在设计抽象方法时,仅以操作成功(例如注册成功、登录成功等)为前提来设计抽象方法的返回值,涉及的操作失败将通过抛出异常来表示!

**创建异常处理:**在cn.demo.store下创建ex子包,并创建异常的父类(ServiceException)

由于需要使用异常来表示错误,所以,在实现抽象方法的功能之前,还应该先定义相关的异常,有哪些“错误”(导致操作失败的原因),就创建哪些异常类,例如,注册时,用户名可能已经被占用,则需要创建对应的异常,当用户名没有被占用,允许注册时,执行的INSERT操作也可能失败,导致相应的异常,为了便于统一管理这些异常,还应该创建自定义异常的基类,这个基类异常应该继承自RuntimeException:

/** * 业务异常的基类 */ public class ServiceException extends RuntimeException { private static final long serialVersionUID = 980104530291206274L; public ServiceException() { super(); } public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } public ServiceException(String message, Throwable cause) { super(message, cause); } public ServiceException(String message) { super(message); } public ServiceException(Throwable cause) { super(cause); } } ----------------------------------------------------------------------------- /** * 用户名冲突的异常 */ public class UsernameDuplicateException extends ServiceException { private static final long serialVersionUID = -1224474172375139228L; public UsernameDuplicateException() { super(); } public UsernameDuplicateException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } public UsernameDuplicateException(String message, Throwable cause) { super(message, cause); } public UsernameDuplicateException(String message) { super(message); } public UsernameDuplicateException(Throwable cause) { super(cause); } } ------------------------------------------------------------------------------- /** * 插入数据异常 */ public class InsertException extends ServiceException { private static final long serialVersionUID = 7991875652328476596L; public InsertException() { super(); } public InsertException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } public InsertException(String message, Throwable cause) { super(message, cause); } public InsertException(String message) { super(message); } public InsertException(Throwable cause) { super(cause); } }

接下来,就需要编写接口的实现类,并实现接口中的抽象方法!所以,在cn.demo.store.service包创建子级的impl包,并在impl包中创建UserServiceImpl类,实现UserService接口,在类的声明之前添加@Service注解,使得Spring框架能够创建并管理这个类的对象!并且,由于在实现过程中,必然用到持久层开发的数据操作,所以,还应该声明UserMapper对象,该对象的值应该是自动装配的:

/** * 处理用户数据的业务层实现类 */ @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public void reg(User user) { } }

接下来,分析实现过程:

public void reg(User user) { // 通过参数user获取尝试注册的用户名 String username = user.getUsername(); // 调用userMapper.findByUsername()方法执行查询 User result = userMapper.findByUsername(username); // 判断查询结果是否不为null if (result != null) { // 是:查询到了数据,表示用户名已经被占用,则抛出UsernameDuplicationException throw new UsernameDuplicateException(); } // 如果代码能执行到这一行,则表示没有查到数据,表示用户名未被注册,则允许注册 // 创建当前时间对象: Date now = new Date(); // 向参数user中补全数据:salt, password,涉及加密处理,暂不处理 // 向参数user中补全数据:is_delete(0) user.setIsDelete(0); // 向参数user中补全数据:4项日志(now, user.getUsername()) user.setCreaser(username); user.setCreatedTime(now); user.setModifiedUser(username); user.setModifiedTime(now); // 调用userMapper.insert()执行插入数据,并获取返回的受影响行数 Integer rows = userMapper.insert(user); // 判断受影响的行数是否不为1 if (rows != 1) { // 是:插入数据失败,则抛出InsertException throw new InsertException(); } }

然后,应该在src/test/java下的cn.demo.store包中创建子级的service包,并在这个包中创建UserServiceTests测试类,专门用于测试UserService接口中定义的功能:

@RunWith(SpringRunner.class) @SpringBootTest public class UserServiceTests { @Autowired private UserService service; @Test public void reg() { try { User user = new User(); user.setUsername("service"); user.setPassword("1234"); user.setGender(0); user.setPhone("13800138003"); user.setEmail("[email protected]"); user.setAvatar("avatar"); service.reg(user); System.err.println("OK."); } catch (ServiceException e) { System.err.println(e.getClass().getName()); } } }

最后,还应该处理密码加密(添加commons-codec依赖),完整业务代码例如:

/** * 处理用户数据的业务层实现类 */ @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public void reg(User user) { // 日志 System.err.println("UserServiceImpl.reg()"); // 通过参数user获取尝试注册的用户名 String username = user.getUsername(); // 调用userMapper.findByUsername()方法执行查询 User result = userMapper.findByUsername(username); // 判断查询结果是否不为null if (result != null) { // 是:查询到了数据,表示用户名已经被占用,则抛出UsernameDuplicationException throw new UsernameDuplicateException(); } // 如果代码能执行到这一行,则表示没有查到数据,表示用户名未被注册,则允许注册 // 创建当前时间对象: Date now = new Date(); // 向参数user中补全数据:salt, password String salt = UUID.randomUUID().toString(); user.setSalt(salt); String md5Password = getMd5Password(user.getPassword(), salt); user.setPassword(md5Password); // 向参数user中补全数据:is_delete(0) user.setIsDelete(0); // 向参数user中补全数据:4项日志(now, user.getUsername()) user.setCr


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有