MVC - 添加DAO和Service层

表间的查找

在上一篇文章结束后,数据库中添加两张表,一张用于表明用户间的好友关系:

另一张用于存储各用户的登录信息:

由此添加一个DAO接口及其实现类,用于将用户的登录信息以对象存储,此pojo的属性如下:

private Integer id;
private String loginId;
private String nickName;
private String pwd;
private UserDetail userDetail;  //此用户细节信息
private List<UserLogin> friendList;   //此用户的好友列表

需要注意的是,UserDetail、friendList这两个属性是不能从数据库中读取到的,所以BaseDAO的执行并不会填充这些属性,它们的作用在于登陆成功后,通过DAO或Service手动获取对应Detail和List,然后使用setter方法将这些属性填充,最后将整个对象存入Session中保存

UserLogin的DAO中有四个方法,分别是:

UserLogin getUserLoginById(int id);  //根据id查找用户登录信息
UserLogin getUserLoginByPwd(String loginId, String pwd);   //根据账号密码查找用户登录信息,用于登录验证
List<UserLogin> getTempFriendList(UserLogin userLogin);  //根据传入的UserLogin对象的id查找该对象的所有好友
void addUserLogin(UserLogin userLogin);  //添加一个用户

第三个方法返回的是一个UserLogin的数组,而一般来说,查找到的结果只能是一串id值,这里就借助到BaseDAO中已经编写好的“返回对象数组”的方法,直接将查到的好友id填充到新的实例中去,最后将这一系列好友实例组成列表并返回即可。这里方法名带了一个Temp,意思就是说返回的这个数组并不是真的好友对象的列表,而只是一个临时的、仅存储了id的对象

为什么一定要返回List<UserLogin>?为什么不能只返回id?反正最后都需要通过id拿到真正的friend对象,何必多此一举?

是因为BaseDAO要么返回单个对象,要么返回对象列表,并不能返回一串数组或是其他的什么,这是对BaseDAO的妥协

​BaseDAO中,负责将搜索结果装填为对象的方法是setValues,在其中是通过名称来查找传入对象的对应属性并装填的,因此,要让id被装填,必须也让查找的结果列名为id,如此一来,BaseDAO才能正确地找到属性并赋值,所以,使用以下的SQL语句来进行查找:

select friend as id from relations where uid=?

在如此搜索后,得到的结果集列名仍是friend,百度后得知需要在数据库连接url中指定useOldAliasMetadataBehavior为true(以提交表单的形式),设置后运行正常:

 如此一来,就完成了UserLoginDAO及其实现类的编写

接下来,进行Service的的引入

Service接口和实现类

Service层负责将多个DAO操作整合成一整个具有原子性的、不可分割的操作,最后返回结果

计划新建一个UserLoginService接口,实现“用户登录”、“获取用户好友”的服务


用户登录的服务逻辑是:拿到输入的loginId和pwd,然后在数据库中查询,返回查询的结果。此处可以不用判断查询结果,因为Service接口仅是单纯调用DAO的通道,判断查询结果的事情要交给Controller做。在此先明确一下以后Controller做的事情:若能查到,说明用户信息输入正确,返回此用户的登录信息;若查不到,则说明用户名或密码搜索错误。

在这个过程中需要调用的DAO:根据账号密码查询登录信息


获取用户好友时,首先调用DAO中的方法获取临时好友列表,再根据这些临时对象的id属性,调用相应DAO拿到真实的好友对象列表

在这个过程中需要调用的DAO:根据传入对象查找所有好友根据id查找所有用户登录信息


所以,得到如下Service接口:

public interface UserLoginService {
    UserLogin login(String loginId, String pwd);  //提交登录
    List<UserLogin> getFriendList(UserLogin userLogin);   //得到好友对象列表
}

在进行此服务接口的实现时,在此处我们选择直接将UserLoginDAOImpl进行实例化,在以后进行IOC控制反转的时候再为其赋null值

public class UserLoginServiceImpl extends BaseDAO<UserLogin> implements UserLoginService {
    UserLoginDAO userLoginDAO = new UserLoginDAOImpl();
    @Override
    public UserLogin login(String loginId, String pwd) {
        return userLoginDAO.getUserLoginByPwd(loginId,pwd);
    }

    @Override
    public List<UserLogin> getFriendList(UserLogin userLogin) {
        List<UserLogin> temp = userLoginDAO.getTempFriendList(userLogin);
        List<UserLogin> res = new ArrayList<UserLogin>();
        for(UserLogin friend : temp) {
            friend = userLoginDAO.getUserLoginById(friend.getId());
            res.add(friend);
        }
        return res;
    }
}

如此一来,Service层就编写完毕了,由于当前只有两个DAO,且UserDetailDAO的作用还不明显,因此Service的业务逻辑较为简单,我会在之后的学习中逐渐扩充DAO的数量,并完善业务逻辑

最后,进行Service层的测试:

public class ServiceTest {
    public static void main(String[] args) throws SQLException {
        UserLoginService u = new UserLoginServiceImpl();
        UserLogin t = u.login("u03","003");
        System.out.println(t + "的好友为:");
        List<UserLogin> res = u.getFriendList(t);
        for (UserLogin userLogin : res)
            System.out.println(userLogin);
    }
}

测试结果:

最后,再编写、实现UserDetailDAO的Service,其接口为:

public interface UserDetailService {
    UserDetail getDetailById(int id);  //根据id获取UserDetail
}

这个Service可以帮助Controller进行要装填信息的获取,如通过登陆成功后拿到的UserLogin去找其对应的UserDetail

实现类代码略

posted @ 2022-09-05 09:39  FICeN  阅读(155)  评论(0)    收藏  举报