《5K入门级项目实战:好来屋在线影院》之第 3 战 —— 项目框架搭建、实现基础的CRUD(增删改查)

很多同学对“框架”的概念不是很了解,可以了解一下:https://baike.so.com/doc/1863840-1971314.html

问:什么是框架?

答:框架(Framework)是构成软件可复用设计的一组相互协作的类。它规定了你的应用体系结构,定义了整体结构、类、对象的分割,各个部分主要负责分内的工作。举个简单例子:起楼房。要起一栋楼房,工程师们会先在图纸上画好房屋的整体结构,比如大厅、卧室、楼梯间、门窗等,然后采购的人才考虑用什么砖、水泥、沙子等。并不是一上来就砌砖。好的架构,可以把问题划分开来各个解决,让系统开发易于控制、易于管理、易于扩展。这就是系统开发要求的“高内聚、低耦合”的宗旨了。

实现基础的 CRUD 

CRUD(增删改查,create、read、update、delete的缩写)操作,接下来,我们对表 user_account 做简单的增删改查功能,以打通数据从“前端——》后台——》数据库——》后台——》前端” 这条闭环之路。

1、我们先在 pom.xml  配置文件里添加 mybatis 依赖和 SpringBoot 的相关依赖,pom.xml 配置文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<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>com.movie</groupId>
    <artifactId>haolaiwu-movie</artifactId>
    <version>1.0.0</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.8.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 数据库MySQL 依赖包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>
        <!-- mybatis 依赖包 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <!-- 该 starter 会扫描配置文件中的 DataSource,然后自动创建使用该 DataSource 的 SqlSessionFactoryBean,并注册到 Spring 上下文中 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>
        <!-- 阿里巴巴的druid数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.20</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <!-- mybatis generator 自动生成代码插件 -->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.7</version>
                <configuration>
                    <configurationFile>${basedir}/src/main/resources/mybatis-generator.xml</configurationFile>
                    <overwrite>true</overwrite>
                    <verbose>true</verbose>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

说明:

我们在 pom.xml 配置里引入“org.mybatis.spring.boot”依赖,SpringBoot 在启动的时候,会自动检测现有的 DataSource 配置,然后创建并注册 SqlSessionFactory 实例,该实例使用 SqlSessionFactoryBean 将该 DataSource 作为输入进行传递,然后创建  SqlSessionTemplate 实例,自动扫描 mapper 文件,然后注入到 Spring 上下文中。

我们再使用 mybatis-spring-boot-starter ,只需要定义一个 DataSource 即可(可以在配置文件里完成),它会自动创建使用该 DataSource 的。可以关注接下来的 application.yml 配置文件。

2、接着,我们在 database 这个包下,先创建两个包:dao service。然后在 dao 包下创建接口UserAccountDao,在 service 包下创建类:UserAccountService。如图:

说明:

①dao 包主要存放操作数据库的接口类,里面的方法名对应 mapper.xml 里的 id。

②service 包其实可以不使用,加多一层,主要是为了实现数据库事务的控制(待会再说)。

UserAccountDao 需要增加 @Mapper 注解,以便与 mapper.xml 文件映射。完整代码如下:

package com.movie.database.dao;

import com.movie.entity.UserAccountEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

/**
 * @author biandan
 * @signature 让天下没有难写的代码
 * @create 2019-11-05 下午 10:55
 */
@Mapper
public interface UserAccountDao {

    //新增用户信息
    int insert(UserAccountEntity userAccountEntity);

    //根据主键 id 删除
    int delete(@Param("id")Integer id);

    //更新用户信息
    int update(UserAccountEntity userAccountEntity);

    //根据主键 id 查询用户信息
    UserAccountEntity selectById(@Param("id")Integer id);
}

说明:UserAccountDao 这个接口我们定义 4 个函数,分别对用户信息实现增删改查。需要注意的是增加 @Mapper 注解。

如果不在 Dao 层添加 @Mapper 注解,可以在启动的类加上:@MapperScan("com.movie.database.dao") 注解,扫描的是Dao层的包。这样就不需要在每个 Dao 类里加入注解 @Mapper 了。

@Param 这个注解非必须,只有一个参数的时候可以不增加,有多个参数的时候最好增加,以保证程序能正确识别参数。

 

UserAccountService 的完整代码如下:

package com.movie.database.service;

import com.movie.database.dao.UserAccountDao;
import com.movie.entity.UserAccountEntity;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author biandan
 * @signature 让天下没有难写的代码
 * @create 2019-11-05 下午 10:45
 */
@Service
public class UserAccountService {

    //自动注入 UserAccountDao 对象
    @Autowired
    private UserAccountDao userAccountDao;

    //新增用户信息。
    //@Transactional(readOnly = false) //readOnly 的事务默认为 false,有读写的操作,可以不设置
    public int insert(UserAccountEntity userAccountEntity){
        return userAccountDao.insert(userAccountEntity);
    }

    //删除用户信息
    //@Transactional(readOnly = false) //readOnly 的事务默认为 false,有读写的操作,可以不设置
    public int delete(@Param("id") Integer id){
        return userAccountDao.delete(id);
    }

    //更新用户信息
    //@Transactional(readOnly = false) //readOnly 的事务默认为 false,有读写的操作,可以不设置
    public int update(UserAccountEntity userAccountEntity){
        return userAccountDao.update(userAccountEntity);
    }

    //根据主键 id 查询用户信息
    @Transactional(readOnly = true)//只读的权限
    public UserAccountEntity selectById(@Param("id") Integer id){
        return userAccountDao.selectById(id);
    }
}

说明:

@Transactional(readOnly = false) 这个注解是控制数据库事务的注解,可以在有需要的方法签名处加上。

 

接下来,我们修改 UserAccountEntityMapper.xml 这个 mapper 文件。

首先,namespace 这个属性的值就是我们匹配的 Dao 层的某个接口的全路径,即 UserAccountDao 的全路径,我们需要修改。看演示图,如何找到 UserAccountDao 的全路径:对着 UserAccountDao 这个接口鼠标右键,找到“Copy Reference”,然后粘贴到 namespace 这个属性值里。

结果如下。对应的,我们也把 UserAccountEntity 的路径粘贴到 type 的属性值里。 

很多人对 insert 语句有疑惑:

因为我们数据库表设计的时候就让主键 id 自增了,所以可以用更简单的写法来操作。让数据库去管理自增长的 id 就好。

完整的 UserAccountEntityMapper.xml 内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.movie.database.dao.UserAccountDao">
  <resultMap id="BaseResultMap" type="com.movie.entity.UserAccountEntity">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="user_name" jdbcType="VARCHAR" property="userName" />
    <result column="password" jdbcType="VARCHAR" property="password" />
  </resultMap>

  <!-- 根据主键 id 删除 -->
  <delete id="delete" parameterType="java.lang.Integer">
    delete from user_account
    where id = #{id,jdbcType=INTEGER}
  </delete>

  <!-- 新增用户信息 -->
  <insert id="insert" parameterType="com.movie.entity.UserAccountEntity">
    insert into user_account (user_name, password)
    values (#{userName,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR})
  </insert>

  <!-- 更新用户信息 -->
  <update id="update" parameterType="com.movie.entity.UserAccountEntity">
    update user_account
    <set>
      <if test="null != userName ">
        user_name = #{userName,jdbcType=VARCHAR},
      </if>
      <if test="null != password ">
        password = #{password,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>

  <!-- 根据主键 id 查询用户信息 -->
  <select id="selectById" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select id, user_name, password
    from user_account
    where id = #{id,jdbcType=INTEGER}
  </select>
  
</mapper>

说明:对于 mybatis 不熟悉的朋友们,可以去以下网址自学:https://mybatis.org/mybatis-3/zh/getting-started.html

还有,对于 Mybatis 逆向工程生成的实体类:UserAccountEntity,基本是定义了数据库的字段属性,并提供 get/set 方法。如果有代码简洁强迫症的同学,可以把注解去掉,顺便加一个序列化ID,在互联网行业做开发这个比较重要。IDEA 工具如何生成序列化ID 可以查看我的博客:https://blog.csdn.net/BiandanLoveyou/article/details/102944164

我们先删除 mybatis 自动生成的 get/set 方法,只留下实体类的属性,然后使用快捷键:Alt + Insert,就可以调出小菜单,选中 Getter and Setter 即可。然后 Ctrl + A 全选属性,点击 OK 即可生成 get/set 方法。我的博客里有讲解 IDEA 的快捷键:https://blog.csdn.net/BiandanLoveyou/article/details/101481418

完整 UserAccountEntity 代码如下(序列化 ID 每个人的都不同,仅供参考):

package com.movie.entity;

import java.io.Serializable;

public class UserAccountEntity implements Serializable{

    private static final long serialVersionUID = -6448649226914446277L;
    
    private Integer id;

    private String userName;

    private String password;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

接下来,我们编写 manage 层,主要做业务逻辑处理,对外暴露的是接口。在 manage 包下创建接口UserAccountManage

完整的 UserAccountManage 接口代码如下,注意与 UserAccountService 的差别,二者都是接口,但性质不同,我们定义成布尔类型,便于做逻辑判断:

package com.movie.manage;

import com.movie.entity.UserAccountEntity;
/**
 * @author biandan
 * @signature 让天下没有难写的代码
 * @create 2019-11-06 下午 10:32
 */
public interface UserAccountManage {

    //新增用户信息。
    boolean insert(UserAccountEntity userAccountEntity);

    //删除用户信息
    boolean delete(Integer id);

    //更新用户信息
    boolean update(UserAccountEntity userAccountEntity);

    //根据主键 id 查询用户信息
    UserAccountEntity selectById(Integer id);
}

接下来,我们编写 manage 的实现类:UserAccountManageImpl

先新建一个包:impl,用来存放所有的实现类。

在 impl 包里创建实现类:UserAccountManageImpl

 

编写 UserAccountManageImpl 实现类的时候,需要实现 UserAccountMange 接口,然后重写接口的所有方法。这里说个小技巧:如下图,在敲完代码 implements UserAccountManage 后,我们把鼠标的光标点击到 UserAccountManage,然后使用快捷键:Alt + Enter(回车),选中“Implement methods”,就可以重写接口的所有方法了。靠谱!

UserAccountManageImpl 完整代码如下:

package com.movie.manage.impl;

import com.movie.database.service.UserAccountService;
import com.movie.entity.UserAccountEntity;
import com.movie.manage.UserAccountManage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author biandan
 * @signature 让天下没有难写的代码
 * @create 2019-11-06 下午 10:43
 */
@Service
public class UserAccountManageImpl implements UserAccountManage {

    @Autowired
    private UserAccountService userAccountService;

    //新增用户信息
    public boolean insert(UserAccountEntity userAccountEntity) {
        boolean flag = false;
        try{
            int count = userAccountService.insert(userAccountEntity);
            if(count > 0){
                flag = true;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return flag;
    }

    //根据主键 id 删除用户信息
    public boolean delete(Integer id) {
        boolean flag = false;
        try{
            int count = userAccountService.delete(id);
            if(count > 0){
                flag = true;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return flag;
    }

    //更新用户信息
    public boolean update(UserAccountEntity userAccountEntity) {
        boolean flag = false;
        try{
            int count = userAccountService.update(userAccountEntity);
            if(count > 0){
                flag = true;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return flag;
    }

    //根据主键 id 查询用户信息
    public UserAccountEntity selectById(Integer id) {
        UserAccountEntity userAccountEntity = null;
        try{
            userAccountEntity = userAccountService.selectById(id);
        }catch (Exception e){
            e.printStackTrace();
        }
        return userAccountEntity;
    }
}

说明:

我们需要在接口的实现类(即 UserAccountManageImpl 类)增加注解,@Service 注解表明这是一个业务层的实现类,而不需要在接口(即 UserAccountManage 类)增加注解,这样符合热拔插式。如果后期有实现类的更改,只需要在实现类增加注解即可。

接下来,我们编写 controller 层:UserAccountController,主要用来处理客户端的请求,并获取业务层 manage 返回的信息。

UserAccountController 完整代码如下:

package com.movie.controller;

import com.movie.entity.UserAccountEntity;
import com.movie.manage.UserAccountManage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * @author biandan
 * @signature 让天下没有难写的代码
 * @create 2019-11-06 下午 11:00
 */
@RestController
@RequestMapping(value = "/user")
public class UserAccountController {

    @Autowired
    private UserAccountManage userAccountManage;

    //新增用户信息
    @ResponseBody
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public Map<String,Object> addUserInfo(HttpServletRequest request) {
        Map<String,Object> map = new HashMap<>();
        map.put("code",-1);
        map.put("message","新增用户信息失败!");
        try {
            //从 request 对象中获取用户名、密码
            String userName = request.getParameter("userName");
            String password = request.getParameter("password");
            //创建用户对象,并注入属性
            UserAccountEntity entity = new UserAccountEntity();
            entity.setUserName(userName);
            entity.setPassword(password);
            //调用 UserAccountManage 接口的新增用户方法
            boolean flag = userAccountManage.insert(entity);
            if(flag){//成功
                map.put("code",0);
                map.put("message","新增用户信息成功!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    //根据 id 删除用户信息
    @ResponseBody
    @RequestMapping(value = "/delete", method = RequestMethod.POST)
    public Map<String,Object> deleteUserInfo(HttpServletRequest request) {
        Map<String,Object> map = new HashMap<>();
        map.put("code",-1);
        map.put("message","删除用户信息失败!");
        try {
            //从 request 对象中获取用户名主键 id
            int id = Integer.parseInt(request.getParameter("id"));
            //调用 UserAccountManage 接口删除方法
            boolean flag = userAccountManage.delete(id);
            if(flag){//成功
                map.put("code",0);
                map.put("message","删除用户信息成功!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    //修改用户信息
    @ResponseBody
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public Map<String,Object> updateUserInfo(HttpServletRequest request) {
        Map<String,Object> map = new HashMap<>();
        map.put("code",-1);
        map.put("message","修改用户信息失败!");
        try {
            //从 request 对象中获取用户名、密码
            Integer id = Integer.parseInt(request.getParameter("id"));
            String userName = request.getParameter("userName");
            String password = request.getParameter("password");
            //创建用户对象,并注入属性
            UserAccountEntity entity = new UserAccountEntity();
            entity.setId(id);
            entity.setUserName(userName);
            entity.setPassword(password);
            //调用 UserAccountManage 接口的修改用户方法
            boolean flag = userAccountManage.update(entity);
            if(flag){//成功
                map.put("code",0);
                map.put("message","修改用户信息成功!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    //根据主键 id 查询用户信息
    @ResponseBody
    @RequestMapping(value = "/select", method = RequestMethod.POST)
    public UserAccountEntity selectUserInfo(HttpServletRequest request) {
        UserAccountEntity entity = null;
        try {
            //从 request 对象中获取用户名主键 id
            int id = Integer.parseInt(request.getParameter("id"));
            //调用 UserAccountManage 接口的查询用户方法
            entity = userAccountManage.selectById(id);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return entity;
    }
}

说明:如果使用了 @RestController 来修饰一个类,则方法不需要再使用 @ResponseBody 修饰。

@Controller:修饰class,用来创建处理http请求的对象
@RestController:Spring4之后加入的注解,原来在 @Controller 中返回 json 需要 @ResponseBody 来配合,如果直接用@RestController替代@Controller就不需要再配置@ResponseBody,默认返回 json 格式。
@RequestMapping:配置 url 映射
 

增删改 这3个方法都返回一个 map 对象,map 对象里存了两个 key,如果成功,会把失败对应的 key 的值覆盖。主要给大家体验一下默认返回 json 格式的数据,以及企业中标准接口协议里如何封装返回信息给调用者。

 

接下来,我们创建 SpringBoot 启动类:HaoLaiWuMovieApplication,注意存放的位置,在 movie 包下。

 

HaoLaiWuMovieApplication 完整代码:

package com.movie;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author biandan
 * @signature 让天下没有难写的代码
 * @create 2019-11-06 下午 11:28
 */
@SpringBootApplication
public class HaoLaiWuMovieApplication {

    public static void main(String[] args) {
        SpringApplication.run(HaoLaiWuMovieApplication.class,args);
    }
}

接下来,我们创建 application.yml 配置文件,配置程序启动时加载到 spring 容器的对象。

# 配置服务相关信息
server:
  # 端口号
  port: 8080

# 服务名称和数据源配置
spring:
  application:
    name: haolaiwu
  datasource:
    # 使用阿里巴巴的 druid 数据源
    druid:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/movie?characterEncoding=utf-8
      username: root
      password: 123456

# mybatis 配置
mybatis:
  # Mybatis扫描的mapper文件
  mapper-locations: classpath:mapper/*.xml
  # 扫描哪个包下的对象
  type-aliases-package: com.movie.entity
  # Mybatis配置文件
  config-location: classpath:mybatis-config.xml

最后,我们在 resources 文件夹下创建 mybatis-config.xml 配置文件,与 application.yml 同一级

 

mybatis-config.xml 配置文件完整代码:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
 
    <!-- 全局配置参数 -->
    <settings>
        <!-- 使全局的映射器启用或禁用缓存。 -->
        <setting name="cacheEnabled" value="true"/>
        <!-- debug 模式打印 sql 语句 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
 
</configuration>

 

OK,万事俱备只欠东风。我们来运行启动 HaoLaiWuMovieApplication

项目启动成功:

我们使用 postman 工具,下载 postman 地址:https://www.getpostman.com/downloads/

测试接口:

1、新增用户信息:

我们看到控制台输出 SQL 语句,这主要是我们在 mybatis-config.xml 配置文件加了一行配置代码:

<setting name="logImpl" value="STDOUT_LOGGING"/>

控制台输出信息: 

==>  Preparing: insert into user_account (user_name, password) values (?, ?) 
==> Parameters: biandan(String), nice123(String)
<==    Updates: 1

去数据库查看:

postman 返回结果:

2、修改用户信息(必须传递主键 id):

postman 输出:

查看数据库:

 

3、根据主键 id 查询用户信息:

postman 结果:

4、根据主键 id 删除用户信息:

postman 显示结果:

OK,至此,我们完成了一个项目框架的搭建,并且实现了对数据库表的增删改查。这是最基础的一步,也是最重要的一步。千里之行始于足下,未来可期啊!

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值