SSM框架实例--管理系统--登录注册的功能分析
分析:
登录和注册,都是用户的行为,也是开发中常说的某个行为对应的业务。
注册用户:意味着添加用户,添加了用户后,才有登录功能的继续执行的可能。
用户登录:也是用户信息的查找和比对过程。一般来说用户先把信息提交给程序,然后程序按照流程执行后提交数据给服务器(流程中程序可能会产生一些业务逻辑的判断),服务器收到数据并进行数据对比,当用户信息存在且帐号和密码匹配才能登录成功,否则前面的任意条件不满足即为登录失败。
可以依靠单一的用户表来实现用户的登录数据获取和注册信息的添加。
功能大概分析完毕后,就可以考虑下如何实现这些功能。大概图示如下:
ssm框架经典三层分析
首先用户信息需要存储,需要数据库的支撑。
有了数据库的支撑后,需要先测试用户信息的添加和查找,也就是去数据库的增删改查。就是
Dao
层。
当
Dao
层拿到想要的数据,需要
Service
层将
Dao
层的操作作为服务提供给控制器,再由控制器提供给前台页面。
同样的用户需要获取某个数据,先是浏览器获取到用户请求→
web
层→Service
层→Dao
层,再接着重复上面的操作。
上面一张图用模型已经很好的说明了Java web
后端各层的关系,下面一张图是经典三层对照MVC的描述。
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操作中,需要手动管理数据库连接的开关,数据库资源访问的开关等等,采用了Mybatis
和Druid
这两个框架,那么我们可以完全不必理会数据库连接等等的控制,只需要更加专注于业务实现的开发。
完成UserDao
的封装后,传统的操作这一步需要自己手动实现UserDao
的Impl
,并实现对数据库的操作等等。而我们使用Mybatis
后,UserDao
的Impl
在Mybatis
的mapper
文件夹中指定为xml
,Dao
文件除了数据库操作的语句其他的都无需关注,那么剩下的数据库操作什么的我们都无需关心,毕竟Mybatis
和druid
都把其他的事情帮我们做了。
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
目录下建好对应的目录,建好如下
按照我们编程的原则,一次编码处处运行,我们可以把这些注解放到
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
**
但程序的编译和运行都是没有问题的,这个错误提示并不会产生影响。但红色的错误提示在有些有强迫症的程序员眼里,多多少少有些不太舒服。
原因
spring auto scan
配置,在编辑情况下,无法找不到对应的bean
,于是提示找不到对应bean
的错误。常见于mybatis
的mapper
,如下:
<!-- 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>
- 解决方案
降低Autowired
检测的级别,将Severity
的级别由之前的error
改成warning
或其它可以忽略的级别。
在project→settings中设置Autowired
检测的级别
userDao
的红线消失了
主要参考于大牛Clone丶记忆的SSM集成之路