在上述文章中,已经完成了Springboot环境的搭建、数据库的配置、Pojo、MyBatis映射文件、Dao层、MVC的配置、资源的过滤与拦截、用户的认证与权限等。Spring一般搭配SpringMvc,也就是MVC模式一起使用,那么在MVC中,我们已经完成了model的编写,接下来要写Controller层、Service层如何响应请求、如何请求数据。
在SpringBoot中,有如下常用的注解:
也许,看到这里,你会有些奇怪,什么是Dao层,什么是Service层,Controller层又是什么呢?为什么要用Controller来处理响应呢?@Controller注解与Controller又有什么关系呢?这里就要提到SpringMVC层的概念:
MyBatis-generator工具已经帮我们实现了Dao层的大部分工作,但是我们还需要在Spring配置文件中配置数据源。
首先是Dao层的映射接口:
这里以UserMapper映射为例,如无特殊的需求(将两个实体的数据合并为一个传递给Service),一般而言,Dao层的映射文件都不需要进行修改。接口名字也清晰明了,基本上都是通过主键或者Example来对数据进行条件的筛选,然后筛选后的数据。 这里特别强调 updateByExample、updateByExampleSelective这两个接口:
public interface UserMapper { int countByExample(UserExample example); int deleteByExample(UserExample example); int deleteByPrimaryKey(Integer id); int insert(User record); int insertSelective(User record); List<User> selectByExample(UserExample example); User selectByPrimaryKey(Integer id); int updateByExampleSelective(@Param("record") User record, @Param("example") UserExample example); int updateByExample(@Param("record") User record, @Param("example") UserExample example); int updateByPrimaryKeySelective(User record); int updateByPrimaryKey(User record); } 复制代码
Dao层具体的映射文件如下:
<?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.ljh.dao.UserMapper" > <resultMap id="BaseResultMap" type="com.ljh.po.User" > <id column="id" property="id" jdbcType="INTEGER" /> <result column="name" property="name" jdbcType="VARCHAR" /> <result column="account" property="account" jdbcType="VARCHAR" /> <result column="password" property="password" jdbcType="VARCHAR" /> <result column="role_id" property="roleId" jdbcType="INTEGER" /> </resultMap> <sql id="Example_Where_Clause" > <where > <foreach collection="oredCriteria" item="criteria" separator="or" > <if test="criteria.valid" > <trim prefix="(" suffix=")" prefixOverrides="and" > <foreach collection="criteria.criteria" item="criterion" > <choose > <when test="criterion.noValue" > and ${criterion.condition} </when> <when test="criterion.singleValue" > and ${criterion.condition} #{criterion.value} </when> <when test="criterion.betweenValue" > and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} </when> <when test="criterion.listValue" > and ${criterion.condition} <foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," > #{listItem} </foreach> </when> </choose> </foreach> </trim> </if> </foreach> </where> </sql> <sql id="Update_By_Example_Where_Clause" > <where > <foreach collection="example.oredCriteria" item="criteria" separator="or" > <if test="criteria.valid" > <trim prefix="(" suffix=")" prefixOverrides="and" > <foreach collection="criteria.criteria" item="criterion" > <choose > <when test="criterion.noValue" > and ${criterion.condition} </when> <when test="criterion.singleValue" > and ${criterion.condition} #{criterion.value} </when> <when test="criterion.betweenValue" > and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} </when> <when test="criterion.listValue" > and ${criterion.condition} <foreach collection="criterion.value" item="listItem" open="(" close=")" separator="," > #{listItem} </foreach> </when> </choose> </foreach> </trim> </if> </foreach> </where> </sql> <sql id="Base_Column_List" > id, name, account, password, role_id </sql> <select id="selectByExample" resultMap="BaseResultMap" parameterType="com.ljh.po.UserExample" > select <if test="distinct" > distinct </if> <include refid="Base_Column_List" /> from user <if test="_parameter != null" > <include refid="Example_Where_Clause" /> </if> <if test="orderByClause != null" > order by ${orderByClause} </if> </select> <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" > delete from user where id = #{id,jdbcType=INTEGER} </delete> <insert id="insert" parameterType="com.ljh.po.User" > insert into user (id, name, account, password, role_id) values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{account,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, #{roleId,jdbcType=INTEGER}) </insert> <update id="updateByExample" parameterType="map" > update user set id = #{record.id,jdbcType=INTEGER}, name = #{record.name,jdbcType=VARCHAR}, account = #{record.account,jdbcType=VARCHAR}, password = #{record.password,jdbcType=VARCHAR}, role_id = #{record.roleId,jdbcType=INTEGER} <if test="_parameter != null" > <include refid="Update_By_Example_Where_Clause" /> </if> </update> </mapper> 复制代码
代码有所删减,在该映射文件中首先定义了xml文件的类型,随后定义了User这个类及类属性在数据库中的定义,再定义example,最后就是各个接口文件对于数据库的具体实现。
上述的类、映射文件都是通过数据库逆向生成的,那么如果我需要在SpringBoot中查询某一数据,我该到哪里去查呢?这时候就要定义数据源。在项目的application.properties文件中添加如下配置:
#数据源配置,默认使用tomcate-jdbc连接池 spring.datasource.url=jdbc:mysql://数据库地址:3306/数据库名字?useUnicode=true&characterEncoding=UTF8 spring.datasource.username=用户名 spring.datasource.password=用户密码 spring.datasource.driver-class-name=com.mysql.jdbc.Driver 复制代码
既然已经打通了Dao层与数据库之间的障碍,那么我们来看一下Service层是如何实现他的价值。我觉得写代码时,只要敢想,就没有做不到的事情,一个接口可以完成多种应用场景。灵活,就是我对Service接口的评价。
public interface UserService { ... /** * 注册成功则无异常抛出 * 用户名/手机被使用,则抛出异常 * @param user * @throws ServiceException */ void register(User user) throws ServiceException; /** * 查找相似的user * @param likeUser * @return */ List<User> getUsers(User likeUser); } 复制代码
就这么一个通过传入的user对象来获取类似User的接口,实现方式和应用的场景却是变化万千。 先来看看简单的方式:
@Service public class UserServiceImpl implements UserService { private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class); @Autowired private UserMapper userMapper; //Dao层接口 @Override public List<User> getUsers(User likeUser) { //构造example UserExample example = new UserExample(); UserExample.Criteria criteria = example.createCriteria(); if (null != likeUser) { if (null != likeUser.getId()) { criteria.andIdEqualTo(likeUser.getId()); } if (null != likeUser.getName()) { criteria.andNameLike("%" + likeUser.getName() + "%"); } if (null != likeUser.getAccount()) { criteria.andNameLike("%" + likeUser.getAccount() + "%"); } } return userMapper.selectByExample(example); } } 复制代码
在上面的这个实现方式中,通过对传入的user对象属性进行判断,如果存在,则将该条件添加到example中,随后通过Dao层获取到类似的User数据。这个接口可以用于模糊搜索用户、查看某用户信息、如果用户的属性再复杂一些,就可以实现用户排序等功能。
先来看下Controller层处理Url请求的方式
看看代码实例:
@Controller public class UserController { @Autowired private UserService userService; @RequestMapping(path = {"register"}, method = {RequestMethod.POST}) @ResponseBody public Map<String, Object> register(String account, String password, String name, String code) { Map<String, Object> map = new HashMap<>(); //判断传入的数据是否为空 ... //判断传入的数据格式是否正确 ... //会话状态的验证 Session session = SecurityUtils.getSubject().getSession(); try { User user = new User(); user.setAccount(account); if (name == null) { user.setName(user.getAccount()); } user.setName(name); user.setPassword(password); user.setRoleId(2);//设置用户角色 //调用UserService对用户进行注册操作 userService.register(user); map.put("msg", "注册成功"); return map; } catch (Exception e) { e.printStackTrace(); } return map; } } 复制代码
上述的方法是一个Post的form表单请求,看起来参数很多,有点复杂,那么直接传入一个对象要怎么处理呢?
@RequestMapping(path = {"register"}, method = {RequestMethod.POST}) @ResponseBody public Map<String, Object> register(@RequestBody User user) { Map<String, Object> map = new HashMap<>(); //判断传入的数据是否为空 ... //判断传入的数据格式是否正确 ... //会话状态的验证 ... } 复制代码
使用注解@ResponseBody返回Json格式的数据,如果不使用该注解,则跳转到对应的页面。
整个请求的时序图如下: