1. Spring复习

Spring主要是创建对象和管理对象的框架。

Spring通过DI实现了IoC。

Spring能很大程度的实现解耦。

需要掌握SET方式注入属性的值。

需要理解自动装配。

需要掌握Spring表达式。

需要掌握AOP(暂时没学)。

2. Spring MVC复习

Spring MVC框架是解决了V-C交互的问题,即:服务器端如何接收客户端的请求,并如何给予响应。

需要掌握如何接收请求参数。

需要掌握如何转发数据。

需要掌握转发与重定向。

需要掌握响应JSON数据。

需要掌握统一处理异常的做法。

需要掌握拦截器的使用。

3. MyBatis复习

执行增删改的操作的方法应该返回Integer,表示受影响的行数;

执行查询方法的<select>节点必须配置resultTyperesultMap

执行查询时如果列名与字段名不一致,在查询时需要自定义别名,以保证名称统一;

掌握<resultMap>的配置。

--------------------------------------

1. 项目开发流程

关于项目的开发,首先应该确定需要处理的数据有哪些:商品,用户,收藏,订单,购物车,商品分类,收货地址……

然后,确定这些数据的开发、管理的先后顺序,因为某些数据是必须建立在其它数据基础之上的,例如必须先有用户数据,才可以有订单数据或收货地址数据,另外,不同的数据功能,开发的难度也有差异,应该尽可能的先开发简单的、熟悉的数据功能,然后再开发相对较难的数据功能,所以,以上数据的开发顺序大概可以是:用户 > 收货地址 > 商品分类 > 商品 > 收藏 > 购物车 > 订单……

每种类型的数据的处理,都应该遵循:增 > 查 > 删 > 改。

每个功能的处理,应该:持久层 > 业务层 > 控制器层 > 界面。

核心原则:一次只解决一个问题!

2. 用户-注册-持久层

关于持久层,应该先检查有没有对应的数据库/表,及对应的实体类。

关于数据库:

CREATE DATABASE tedu_store;

USE tedu_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 COMMENT '性别,0-女,1-男',
avatar VARCHAR(50) COMMENT '头像',
phone VARCHAR(20) COMMENT '手机号码',
email VARCHAR(30) 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)
) DEFAULT CHARSET=UTF8;

然后,下载本次项目store.zip,解压到Workspace中,通过Import > Existing Maven Projects导入项目。(可以在spring boot 官网自己生成)

由于以上数据表中关于日志的4个字段是后续每张表都应该有的,则后续的每张表对应的实体类中也应该有4个对应的属性,所以,应该创建实体类的基类来封装这4个字段对应的属性,且,当前项目中的所有实体类都应该继承自该基类:

/**
* 实体类的基类
*/
public abstract class BaseEntity implements Serializable { private static final long serialVersionUID = -6185124879935579311L; private String createdUser;
private Date createdTime;
private String modifiedUser;
private Date modifiedTime; // SET/GET ... }

创建与数据表对应的实体类cn.tedu.store.entity.User

/**
* 用户数据的实体类
*/
public class User extends BaseEntity { private static final long serialVersionUID = 8777086855777796877L; private Integer uid;
private String username;
private String password;
private String salt;
private Integer gender;
private String avatar;
private String phone;
private String email;
private Integer isDelete; // SET/GET ...
}

持久层的开发重点应该分为3个步骤:

1. 分析当前功能所需要执行的SQL语句

当前执行“注册”功能,必然需要执行插入数据操作:

INSERT INTO t_user (
username, password ... modified_time
) VALUES (
?, ?, ... ?
)

为了保证“用户名唯一”,还应该有“根据用户名查询数据”的操作:

SELECT
uid
FROM
t_user
WHERE
username=?

2. 创建接口(如果必要的话),并设计抽象方法

创建cn.tedu.store.mapper.UserMapper接口文件,并在其中添加抽象方法:

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

3. 在XML中配置抽象方法的映射

src/main/resources下创建mappers文件夹,然后复制此前的项目得到UserMapper.xml,配置好该文件中根节点的namespace对应的接口,然后,再配置以上2个抽象方法对应的映射:

<mapper namespace="cn.tedu.store.mapper.UserMapper">

    <!-- 插入用户数据 -->
<!-- Integer addnew(User user) -->
<insert id="addnew">
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"
resultType="cn.tedu.store.entity.User">
SELECT
uid
FROM
t_user
WHERE
username=#{username}
</select> </mapper>

注意:此次并没有在接口文件之前添加@Mapper注解,由于这个注解是添加在接口之前的,则项目中可能出现的多个持久层接口都需要添加该注解,管理起来比较麻烦,所以,改为在执行程序StoreApplication之前添加@MapperScan("cn.tedu.store.mapper")注解,以指定持久层接口所在的包,则后续每个持久层接口都不必再添加@Mapper注解。

最后,在src/test/java下,创建cn.tedu.store.mapper.UserMapperTestCase测试类:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTestCase { @Autowired
private UserMapper mapper; @Test
public void addnew() {
User user = new User();
user.setUsername("root");
user.setPassword("1234");
Integer rows = mapper.addnew(user);
System.err.println("rows=" + rows);
} @Test
public void findByUsername() {
String username = "root";
User user = mapper.findByUsername(username);
System.err.println(user);
} }

3. 用户-注册-业务层

业务层的开发通常也是3个步骤来完成!

1. 规划异常

业务层中的方法的返回值,仅以操作成功为标准,判断是否需要返回某种数据。

由于返回值并不体现操作成功与否,则还需要考虑失败的情况,并抛出对应的异常,通常,建议自定义异常,针对不同的操作错误(操作失败的原因)抛出不同的异常,并且,这些异常都应该继承自RuntimeException(原因后续再讲)。实际做法是自定义ServiceException,是继承自RuntimeException的,而其它自定义的异常都继承自ServiceException

/**
* 业务异常,当前项目中自定义异常类的基类
*/
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);
} }

然后,本次的“注册”功能可能抛出“用户名被占用”和“插入数据失败”错误,则需要创建对应的异常UserConflictExceptionInsertException以备抛出。

2. 在业务层接口中声明抽象方法

在业务层中声明的方法是被控制器层(Controller)调用的,且在实现业务层功能时,需要调用持久层对象中的方法,所以,在参数方面,应该是承上启下的,即:能满足调用和被调用的需求。

创建业务层接口cn.tedu.store.service.IUserService接口,并添加抽象方法:

void reg(User user)
throws UserConflictException, InsertException;

3. 实现接口中的抽象方法

创建cn.tedu.store.service.impl.UserServiceImpl类,实现IUserService接口,在类中声明持久层对象@Autowired private UserMapper userMapper;,在类之前添加@Service注解:

@Service
public class UserServiceImpl
implements IUserService { @Autowired
private UserMapper userMapper; @Override
public void reg(User user) throws UserConflictException, InsertException {
// TODO Auto-generated method stub } }

通常,应该把持久层中声明的抽象方法复制到业务层的实现类中,并且通过持久层对象直接调用来实现方法的功能,这些方法应该是私有的,如果是查询类的方法,应该直接返回调用持久层方法的返回结果,如果是增删改的方法,应该将方法的返回值修改为void,并且,在方法体中,判断调用时的返回结果,如果结果不符合预期,则抛出异常。

基于以上原则,应该在业务层的实现类中添加:

/**
* 插入用户数据
* @param user 用户数据
* @return 受影响的行数
*/
private void addnew(User user) {
Integer rows = userMapper.addnew(user);
if (rows != 1) {
throw new InsertException("增加用户数据时出现未知错误!请联系系统管理员!");
}
} /**
* 根据用户名查询用户信息
* @param username 用户名
* @return 匹配的用户数据,如果没有匹配的数据,则返回null
*/
private User findByUsername(String username) {
return userMapper.findByUsername(username);
}

然后,重写接口中定义的抽象方法,在编写时,应该先分析过程,然后再编写代码:

@Override
public void reg(User user) throws UserConflictException, InsertException {
// 根据user.getUsername()获取用户名匹配的数据
// 检查数据是否为null
// 是:为null,用户名未被占用,则应该补全参数中的属性值
// - 1. 密码加密,并封装
// - 2. 封装salt
// - 3. 封装isDelete,固定为0
// - 4. 封装4项日志数据
// - 执行注册:addnew(user)
// 否:非null,用户名被占用,则抛出UserConflictException
}

分析完成,编写可以完成的部分的代码(暂不包括密码加密与salt的处理):

@Override
public void reg(User user) throws UserConflictException, InsertException {
// 根据user.getUsername()获取用户名匹配的数据
String username = user.getUsername();
User data = findByUsername(username);
// 检查数据是否为null
if (data == null) {
// 是:为null,用户名未被占用,则应该补全参数中的属性值
// TODO - 1. 密码加密,并封装
// TODO - 2. 封装salt
// - 3. 封装isDelete,固定为0
user.setIsDelete(0);
// - 4. 封装4项日志数据
Date now = new Date();
user.setCreatedTime(now);
user.setModifiedTime(now);
user.setCreatedUser(username);
user.setModifiedUser(username);
// - 执行注册:addnew(user)
addnew(user);
} else {
// 否:非null,用户名被占用,则抛出UserConflictException
throw new UserConflictException(
"注册失败!您尝试注册的用户名(" + username + ")已经被占用!");
}
}

完成后,仍编写对应的单元测试:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTestCase { @Autowired
private IUserService service; @Test
public void reg() {
try {
User user = new User();
user.setUsername("admin");
user.setPassword("8888");
user.setPhone("13800138001");
user.setEmail("admin@tedu.cn");
user.setGender(1);
user.setAvatar("http://www.tedu.cn/logo.png");
service.reg(user);
System.err.println("OK.");
} catch (ServiceException e) {
System.err.println(e.getMessage());
}
} }

4. 用户-注册-控制器层

5. 用户-注册-界面

spring boot 搭建基本套路《1》的更多相关文章

  1. Set up HTTP/2 server with Spring Boot 【基于Spring boot搭建http2.0服务器】

    1. Server side With spring boot, we can set up a http server easily. Restcontroller make it easier t ...

  2. maven 聚合工程 用spring boot 搭建 spring cloud 微服务 模块式开发项目

    项目的简单介绍: 项目采用maven聚合工程 用spring boot 搭建 spring cloud的微服务 模块式开发 项目的截图: 搭建开始: 能上图 我少打字 1.首先搭建maven的聚合工程 ...

  3. 自我救赎 → 利用 IDEA 和 Spring Boot 搭建 SSM

    前言 开心一刻 儿子读高中放学回来了,一向不管他学习的我突然来了兴趣,想看看他的学习他的状况,抄起他的数学习题看了起来,当看到 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x ...

  4. 记录一次Spring boot 搭建框架连接Mysql数据库注解事务不回滚的故障

    搭建了一个新框架,使用了spring boot 替换以简化原来繁杂的spring配置,使用Spring注解管理事务,持久层使用mybatis. 连接mysql数据库完成项目的过程中发现不支持事务,因为 ...

  5. 使用Spring Boot搭建应用开发框架(一) —— 基础架构

    Spring的简史 第一阶段:XML配置,在Spring1.x时代,使用Spring开发满眼都是xml配置的Bean,随着项目的扩大,我们需要把xml配置文件分放到不同的配置文件里,那时候需要频繁的在 ...

  6. Spring Boot搭建Web项目常用功能

    搭建WEB项目过程中,哪些点需要注意: 1.技术选型: 前端:freemarker.vue 后端:spring boot.spring mvc 2.如何包装返回统一结构结果数据? 首先要弄清楚为什么要 ...

  7. 如何基于Spring Boot搭建一个完整的项目

    前言 使用Spring Boot做后台项目开发也快半年了,由于之前有过基于Spring开发的项目经验,相比之下觉得Spring Boot就是天堂,开箱即用来形容是绝不为过的.在没有接触Spring B ...

  8. Spring Boot 搭建TCP Server

    本示例首选介绍Java原生API实现BIO通信,然后进阶实现NIO通信,最后利用Netty实现NIO通信及Netty主要模块组件介绍. Netty 是一个异步事件驱动的网络应用程序框架,用于快速开发可 ...

  9. (子文章)Spring Boot搭建两个微服务模块

    目录 1. 创建工程和user-service模块 1.1 创建空工程 1.2 在空工程里新建Module 2. 配置文件 2.1 pom.xml 2.2 application.yml 3. 代码 ...

随机推荐

  1. Django——form组件和ModelForm

    一.原生form实现书城增删改查 1.构建模型并完成数据库迁移 (1)构建书城模型 from django.db import models # Create your models here. # ...

  2. 【代码笔记】Java连连看项目的实现(2)——JTable 、TableModel的使用

    博客有时间就写写,所以一篇可能会拆成很多篇,写完后计划再合在一起. 首先肯定是要实现连连看的界面. 先准备连连看要的图片.. “LianLianKan”就是项目名称. 当然,如果小白看我的博客想学到什 ...

  3. 关于React的生命周期的解释

    ---恢复内容开始--- ---恢复内容结束---

  4. 深入理解JavaScript函数

    本篇文章主要介绍了"深入理解JavaScript函数",主要涉及到JavaScript函数方面的内容,对于深入理解JavaScript函数感兴趣的同学可以参考一下. JavaScr ...

  5. vim右键粘贴 等杂

    putty连上linux,vim编辑个文件,我去,右键不能用用上下面的命令,就好了. set mouse-=a 今天发现mysql倒入utf-8的文件网站显示出来都是乱码,不过用utf-8的控制台看是 ...

  6. Fragstats:使用R软件读取frag78b.asc文件

    Fragstats中,有一个用于熟悉Fragstats软件的demon,在tutorial中的1种,有reg78b.asc文件,其文件内容是包含了山歌图像的行数和列数以及分辨率大小等基本信息. 采用R ...

  7. Android 环信聊天头像昵称显示解决方案

    从消息扩展中获取昵称和头像 昵称和头像的获取:把用户基本的昵称和头像的URL放到消息的扩展中,通过消息传递给接收方,当收到一条消息时,则能通过消息的扩展得到发送者的昵称和头像URL,然后保存到本地数据 ...

  8. maven学习(三)maven仓库

    官网图片: maven仓库: 仓库通常配置在settings.xml文件中,此处注意settings.xml的优先级:用户 > 全局,广义上maven的仓库一共包含两种: 1.本地仓库,默认在& ...

  9. React学习笔记 - 组件&Props

    React Learn Note 4 React学习笔记(四) 标签(空格分隔): React JavaScript 三.组件&Props 组件可以将UI切分成一些独立的.可复用的部件,这样你 ...

  10. 离线安装wxpython

    离线安装wxpython 前言 由于工作环境,我的工作机是在离线环境下的,没法连接外网.但是自己又想学习一下wxpython,只好自己手动离线安装,本来以为很简单的,但是实际上...一言难尽. 基本环 ...