继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

spring boot 搭建基本套路《1》

暮色呼如
关注TA
已关注
手记 247
粉丝 86
获赞 309

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)
@SpringBootTestpublic 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注解:

复制代码

@Servicepublic 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);
}

复制代码

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

复制代码

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

复制代码

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

复制代码

@Overridepublic 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)
@SpringBootTestpublic 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. 用户-注册-界面

原文出处:https://www.cnblogs.com/topzhao/p/10335580.html 

作者:Top丶赵立全  

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP