实体list 查找一个符合条件的实体并返回其中一个字段_STEP4.4 写一个简易登录模块...

在STEP3.2 服务器对于HTTP请求的处理流程中,我们认识了一个后端服务应该有的项目结构(Controller,Service,Dao),以及基本调用流程(Controller→Service→Dao);

在STEP4.1 第一个SpringBoot项目中,我们认识了yml全局配置文件,学会了如何写一个服务(/hello),以及如何启动、访问我们的服务;

在STEP4.2 认识pom.xml中,我们认识了SpringBoot依赖Maven来帮助我们的项目进行管理。

在STEP4.3 会话中,我们了解了会话的基本概念,并做了Cookie和HttpSession的简单实践。

到这里,我们应该已经能够自行搭建一些我们想要的服务了。我们来做一个稍微综合一点的实践,来实现一个简易登录模块。也就是我们在4.1节中提到的需求。


我们先来回顾一下老板的三个需求:

  1. 用户可以通过账号密码登录
  2. 已经登录的用户可以查看全用户名列表(没登录就不能看)
  3. 用户可以注销

注:

  1. 由于我们目前已学的内容中不涉及数据库的连接,我们会手写dao层的方法来模拟数据访问。
  2. 考虑到Controller层依赖Service层,Service层依赖Dao层。为了方便叙述,我们从Dao开始自底向上编码,但实际开发过程中势必会在三层间有多次辗转(比如写Controller的时候突然发现自己又需要一个新服务,所以又切换回去给service添加一个方法)。

接下来,既然需求定档了,就让我们开始动代码吧!


一、新建项目并分层

235c14c4efb4d282a9b2ba250376d4f1.png

controller,service,dao大家都已经很熟悉了。这里的entity文件夹我们一般会称之为“实体层”,但它严格来说不算一个层次,因为它并不在我们的http请求处理流程(控制-服务-数据访问)里面。entity包里一般会存POJO(一般java对象)的类,比如User用户类、Student学生类等等,一般会与数据库的表一一对应。


二、构建用户实体

我们先在entity里写一个User类,来表达我们的用户信息:

User类中有以下字段:

ceb136b2cff1fee624faa735f0b625ef.png
user表结构

我们在类中添加一个无参构造器、一个全参构造器、以及所有的getter/setter方法。

public class User {

    private Integer id;
    private String username;
    private String password;

    public User() {
    }

    public User(Integer id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = 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;
    }
}

三、手写dao层接口方法,模拟数据

我们根据一开始提出的几个需求来设计一下dao层的接口:

import java.util.List;

public interface UserDao {

    //获取全用户列表
    List<User> getUserList();

    //获取全用户名列表
    List<String> getUsernameList();

    //根据用户名搜索用户
    User getUserByUsername(String username);

    //根据用户名密码搜索用户
    User getUserByUsernameAndPassword(String username,String password);

}

为什么要用接口而不是直接写类?如果你对这个问题感到好奇,请参考这篇文章:

为什么dao层和service层要用接口?​blog.csdn.net

然后我们对dao层接口进行一个实现:(无需在意实现细节,注意返回内容即可。在之后引入ORM框架mybatis后,这里都应该用SQL语言来进行查询,而不是用代码模拟)

import java.util.ArrayList;
import java.util.List;

public class UserDaoImpl implements UserDao {
    @Override
    public List<User> getUserList() {
        //模拟从数据库取出两条数据,分别是id=1和id=2的用户,并返回
        User user1 = new User(1,"Jack","qwe");
        User user2 = new User(2,"Mary","asd");
        List<User> userList = new ArrayList<>();
        userList.add(user1);
        userList.add(user2);
        return userList;
    }

    @Override
    public List<String> getUsernameList() {
        List<User> userList = getUserList();
        List<String> usernameList = new ArrayList<>();
        for(User user:userList){
            usernameList.add(user.getUsername());
        }
        return usernameList;
    }

    @Override
    public User getUserByUsername(String username) {
        List<User> userList = getUserList();
        for(User user:userList){
            if((user.getUsername()+"").equals(username)){
                return user;
            }
        }
        //如果找不到该用户就返回null
        return null;
    }

    @Override
    public User getUserByUsernameAndPassword(String username, String password) {
        User user = getUserByUsername(username);
        if((user.getPassword()+"").equals(password))return user;
        return null;
    }
}

我们使用这段代码模拟了从数据库取数据的操作。

相当于假定了数据库有这样两个用户:

26414f73852d3142cce3a3c4e425598a.png

四、构建服务层

还是先构建接口

import java.util.List;

public interface UserService {

    //根据用户名密码获取用户
    User getUser(String username, String password);

    //获取用户名列表
    List<String> getUsernames();

}

再实现服务

import java.util.ArrayList;
import java.util.List;

public class UserServiceImpl implements UserService {

    private UserDao userDao = new UserDao();

    @Override
    public User getUser(String username,String password) {
        User user = userDao.getUserByUsernameAndPassword(username,password);
        if(user == null)throw new RuntimeException();
        return user;
    }

    @Override
    public List<String> getUsernames() {
        return new ArrayList<>(userDao.getUsernameList());
    }
}

注:这里有一个throw new RuntimeException,含义是“如果用户登录时用户名找不到或密码错误,就向控制层抛出一个运行时异常”。这个异常类理应由开发者自行设计,不要用java自带的RuntimeException,而是自行设计一个RuntimeException的子类,来捎带一些必要的信息(如错误信息文本,异常代码等)。此处为了方便,不作子类设计。


五、设计接口,开发控制层

先写一个登录控制器

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import undestiny.logindemo.service.UserService;

import javax.servlet.http.HttpSession;

@RestController
public class LoginController {

    private UserService userService = new UserService();

    @GetMapping("/login/{username}/{password}")
    public String login(@PathVariable(value = "username",required = true)String username,
                        @PathVariable(value = "password",required = true)String password,
                        HttpSession session){

        //参数校验
        if(username.length() < 2 || username.length() > 20
                || password.length() < 2 || password.length() > 20){
            return "Login failed";
        }

        //请求转发,会话管理
        try{
            session.setAttribute("user",userService.getUser(username,password));
        }catch (RuntimeException e){
            return "Login failed";
        }
        return "Login successfully";
    }


    @GetMapping("/logout")
    public String logout(HttpSession session){
        //注销session(在服务器里删除该session)
        session.invalidate();
        return "Logout successfully";
    }


}

再写一个用户控制器(提供查看用户名列表的方法)

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import undestiny.logindemo.service.UserService;

import javax.servlet.http.HttpSession;
import java.util.List;

@RestController
public class UserController {

    private UserService userService = new UserService();

    @GetMapping("/getUsernames")
    public List<String> getUsernames(HttpSession session){
        //检查是否登录(session是否存在)
        if(session.getAttribute("user") != null) {
            return userService.getUsernames();
        }
        return null;
    }

}

六、启动服务

在我们的启动类xxxApplication.java上右键运行,打开我们的浏览器进行测试:

首先输入http://localhost:8080/login/Jack/qwe回车

d4ecfdc479c2fb3666d1524789bfde59.png

然后我们输入http://localhost:8080/getUsernames试一下:

73fbae6c87d8231890a3e637e92ddb2c.png

由于此时是登录状态,所以可以获取到用户名列表。

我们尝试注销:输入http://localhost:8080/logout回车

2bad46336dbe02bf1fe994dd1a79dc51.png

然后再尝试获取用户名列表:

26768cb68f883b4a931c3d9d81f33d53.png

由于没有登录,就获取不到用户名列表了。

最后附上我们login-demo的项目源码:

undestiny/JavaWeb后端学习小组​gitee.com
978ba053d6b4ccf0b4499b6b37044203.png

不过细心的读者可能会发现,源码里的和本篇博客中的内容有细微的出入。

这是因为源码中已经根据Spring IOC的特性做了简单优化。请移步下一篇:

孑辞:STEP4.5 初识SpringIOC​zhuanlan.zhihu.com
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值