且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

spring+springMVC+mybatis的整合 part4

更新时间:2022-08-12 16:14:45

SSM框架实例--管理系统--登录注册的功能分析

分析:
登录和注册,都是用户的行为,也是开发中常说的某个行为对应的业务
注册用户:意味着添加用户,添加了用户后,才有登录功能的继续执行的可能。
用户登录:也是用户信息的查找和比对过程。一般来说用户先把信息提交给程序,然后程序按照流程执行后提交数据给服务器(流程中程序可能会产生一些业务逻辑的判断),服务器收到数据并进行数据对比,当用户信息存在且帐号和密码匹配才能登录成功,否则前面的任意条件不满足即为登录失败
可以依靠单一的用户表来实现用户的登录数据获取注册信息的添加

功能大概分析完毕后,就可以考虑下如何实现这些功能。大概图示如下:

spring+springMVC+mybatis的整合 part4

ssm框架经典三层分析
首先用户信息需要存储,需要数据库的支撑。
有了数据库的支撑后,需要先测试用户信息的添加和查找,也就是去数据库的增删改查。就是Dao层。
Dao层拿到想要的数据,需要Service层将Dao层的操作作为服务提供给控制器,再由控制器提供给前台页面。
同样的用户需要获取某个数据,先是浏览器获取到用户请求→web层→Service层→Dao层,再接着重复上面的操作。

上面一张图用模型已经很好的说明了Java web后端各层的关系,下面一张图是经典三层对照MVC的描述。

spring+springMVC+mybatis的整合 part4

ssm框架经典三层分析对照Mvc
上面图中,可以看到一部分MVC设计和图中标记的类似,但是这只是一种MVC模式的栗子。
关于更加详细的MVC,我们可以百度百科查看。

SSM框架实例--管理系统--注册、登录的功能模拟实现
所以在开发的时候需要先考虑Dao层的实现,毕竟有了Dao层对数据的封装,才可以有后面的操作。
一切都是按照Dao→Service→Controller→View这样的一个步骤来实现。

用户注册功能的Dao层实现。

数据库基本操作为:增删改查。
根据数据库常规操作的类型,分别对其进行抽象,所以产生了Dao.java这个接口对象的基本模型。代码如下:
使用泛型,<T> 泛型用于解耦,同时避免写重复代码

public interface Dao<T> {
    /**
     * 添加某个对象
     * @param t 待添加的对象
     * @return  返回受影响的行数
     */
    int add(T t);

    /**
     * 删除某个对象,在企业开发中,我们一般不做物理删除,只是添加某个字段对其数据进行可用控制
     * @param t 待删除对象
     * @return 返回受影响的条数
     */
    int  delete(T t);

    /**
     * 更新某个对象
     * @param t 待更新对象
     * @return 返回受影响的条数
     */
    int update(T t);

    /**
     * 通过ID查找一个对象
     * @param Id    待查询的对象的ID
     * @return  返回该ID对应的对象
     */
    T findOneById(Serializable Id);

    /**
     * 查找对象集合
     * @return  返回对象集合
     */
    List<T> findAll();
}

创建用户实体类,需要封装一个用户对象,直接在domain包下面创建类User
实现Serializable接口是为了序列化。方便网络传输等,传递对象的时候,序列化

public class User implements Serializable{
    private String name;    //名字
    private String sex; //性别
    private String loginId; //登陆ID
    private String pwd;    //密码
    private String duty;    //职务
    private int age;    //年龄
    private String cellNumber;  //手机号
    private String photoUrl;    //头像地址
    private boolean used = true;   //是否可用,默认值是true
    private String nextUrl; //下一步的的操作地址  
    //省略get、set和toString
}

sessionId不需要封装在实体类中
数据库中对应的用户表user

CREATE TABLE `user` (
`login_id` varchar(20) NOT NULL COMMENT '登陆ID',
`pwd` varchar(20) NOT NULL COMMENT '用户密码',
`name` varchar(100) NOT NULL COMMENT '用户姓名',
`age` int(3) NOT NULL COMMENT '用户年龄',
`sex` varchar(3) NOT NULL COMMENT '性别',
`duty` varchar(15) COMMENT '职务',
`cell_number` varchar(15) COMMENT '手机号',
`photo_url` varchar(75) COMMENT '头像地址',
`used` boolean NOT NULL COMMENT '账号是否可用',
`session_id` varchar(45) COMMENT '当前登录的sessionId',
PRIMARY KEY (`login_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='用户表';

对user表进行操作封装的接口UserDao接口,继承DAO接口,在dao包下

public interface UserDao extends Dao<User>{
    int add(User user);

    int delete(User user);

    int update(User user);

    User findOneById(Serializable Id);

    void updateLoginSession(@Param("sessionId") String sessionId, @Param("loginId")  String loginId);

}

在传统的jdbc操作中,需要手动管理数据库连接的开关,数据库资源访问的开关等等,采用了MybatisDruid这两个框架,那么我们可以完全不必理会数据库连接等等的控制,只需要更加专注于业务实现的开发。

完成UserDao的封装后,传统的操作这一步需要自己手动实现UserDaoImpl,并实现对数据库的操作等等。而我们使用Mybatis后,UserDaoImplMybatismapper文件夹中指定为xmlDao文件除了数据库操作的语句其他的都无需关注,那么剩下的数据库操作什么的我们都无需关心,毕竟Mybatisdruid都把其他的事情帮我们做了。
UserDao.xml:
注意:namespace要指定到对应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">
<!-- namespace指定我们的到具体的bean -->
<mapper namespace="pjb.ssm.dao.UserDao">

    <!--查找-->
    <select id="findOneById" resultType="User" parameterType="String">
    SELECT
    *
    FROM
    `user`
    WHERE
    login_id = #{userId}
    </select>

    <!--增加语句-->
    <insert id="add" parameterType="User">
        INSERT INTO
        `user`
        (`login_id`,`name`,`age`,`sex`,`duty`,`cell_number`,`photo_url`,`pwd`,`used`)
        VALUES
        (#{loginId},#{name},#{age},#{sex},#{duty},#{cellNumber},#{photoUrl},#{pwd},#{used})
    </insert>

    <!-- 删除 -->
    <update id="delete" parameterType="User">
        UPDATE
        `user`
        SET
        `used`=FALSE
        WHERE
        `login_id`=#{loginId};
    </update>

    <!-- 更新用户信息 -->
    <update id="update" parameterType="User">
        UPDATE
        `user`
        SET
        `name`=#{name}, `age`=#{age}, `sex`=#{sex}, `duty`=#{duty}, `cell_number`=#{cellNumber}, `photo_url`=#{photoUrl}
        WHERE
        `login_id`=#{loginId};
    </update>
    <!--更新session的id-->
    <update id="updateLoginSession">
        UPDATE
        `user`
        SET
        `session_id`=#{sessionId}
        WHERE
        `login_id`=#{loginId};
    </update>
</mapper>

mapper下面的UserDao.xml已经完成,这就意味着我们的UserDao基本完成,下面做的是来编写测试类
先在test目录下建好对应的目录,建好如下

Paste_Image.png

按照我们编程的原则,一次编码处处运行,我们可以把这些注解放到BaseTest中,后面所有的单元测试都继承BaseTest即可避免大量重复编码。
BaseTest是主测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring/spring-*.xml"})
public class BaseTest {
}

@RunWith(SpringJUnit4ClassRunner.class)是为了让测试在Spring容器环境下执行。
@ContextConfiguration({"classpath:spring/spring-*.xml"})用于指定配置文件所在的位置
代码非常简单,用与dao,service测试类继承用

UserDaoTest,每个@Test单独测试,由于测试结果不回滚,可以在数据库看到测试是否成功

public class UserDaoTest extends BaseTest {
    @Autowired
    private UserDao userDao;

    @Test
    public void testAdd() {
        User user = new User();
        user.setLoginId("2015081040");
        user.setName("意识流");
        user.setPwd("123456");
        user.setSex("不知道");
        int result = 0; //受影响的行数默认为0
        try {
            result = userDao.add(user);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("添加用户失败");
        }
        if (result>0)
            System.out.println("添加用户成功");
    }

    @Test
    public void testFindOneId() throws Exception {
        User user = new User();
        user.setLoginId("2015081040");
        User result = null; //受影响的行数默认为0
        try {
            result = userDao.findOneById(user.getLoginId());
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("查找用户失败");
        }
        if (null!=result)
            System.out.println("查找用户成功\n"+result.toString());
    }

    @Test
    public void testDelete() {
        User user = new User();
        user.setLoginId("2015081040");
        int result = 0; //受影响的行数默认为0
        try {
            result = userDao.delete(user);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("删除用户失败");
        }
        if (result>0)
            System.out.println("删除用户成功");
    }

    @Test
    public void testUpdate() {
        User user = new User();
        user.setLoginId("2015081040");
        user.setName("pjb");
        user.setPwd("123456");
        user.setSex("男");
        int result = 0; //受影响的行数默认为0
        try {
            result = userDao.update(user);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("更新用户信息用户失败");
        }
        if (result>0)
            System.out.println("更新用户信息用户成功");

    }
}

**在测试的时候可能会发现userDao 显示Could not autowire, No beans of 'UserDao' type found **

Paste_Image.png

但程序的编译和运行都是没有问题的,这个错误提示并不会产生影响。但红色的错误提示在有些有强迫症的程序员眼里,多多少少有些不太舒服。

原因
  spring auto scan配置,在编辑情况下,无法找不到对应的bean,于是提示找不到对应bean的错误。常见于mybatismapper,如下:

<!-- 4.配置扫描Dao接口包,动态实现Dao接口,注入到spring容器中 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 注入sqlSessionFactory -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!-- 给出需要扫描Dao接口包 -->
        <property name="basePackage" value="pjb.ssm.dao"/>
    </bean>
  1. 解决方案
    降低Autowired检测的级别,将Severity的级别由之前的error改成warning或其它可以忽略的级别。
    在project→settings中设置Autowired检测的级别
    Paste_Image.png
    设置完后可以发现userDao的红线消失了

主要参考于大牛Clone丶记忆的SSM集成之路