2.5 完整的程序
在前面的章节中我们学会了构建一个最简单的Blade程序,这节来做一个相对完整的较为简单的Web程序。
这个程序只有一个登陆的功能,用户名和密码暂时写在配置文件中。
这样的一个程序大概可以在脑海里浮现,嗯。。有一个登陆页面,一个提交表单的请求,一个登陆成功后的页面。
还需要一个注销的功能,非常简单的web常用小功能。
我们梳理一下完成这个功能的思路:
- 编写配置文件将用户名密码存储起来
- 创建4个路由(index, login[GET], login[POST], logout)
- 编写login.html, index.html 页面
- 编写登陆逻辑,将登陆成功状态存储在session中
- 编写注销逻辑,将登陆状态从session清除
- 编写一个webhook,用于拦截没有登陆的用户
简单明了,佩服我自己 23333
第一步,加载配置
项目还是继续用之前创建的 first-blade-app
,在 resources
目录下创建一个 app.properties
的配置文件,Blade会在启动的时候加载它,然后我们加入两行配置:
app.username=hello@gmail.com
app.password=blade123
配置加好了,怎么读取呢,头大!!!哈哈,在blade中读取配置的方式非常简单,因为 app.properties
会在启动的时候加载,我们可以利用 Blade 的事件机制,当启动完毕后我们读取一下配置就可以了,怎么做呢?
Blade.me().event(EventType.SERVER_STARTED, (e) -> {
Environment environment = e.blade.environment();
Const.USERNAME = environment.get("app.username").get();
Const.PASSWORD = environment.get("app.password").get();
}).start(Application.class);
这段代码是配置一个启动后执行的事件,将配置文件中的 username
和 password
存储到常量中去。
第二步,创建路由
虽然项目非常的小,你可以不用创建包,直接写在主类里或者写一个 Controller
,为了让大家养成良好的编码习惯,我还是将控制器写在 controller
子包中。
@Path
public class AuthController {
@GetRoute("index")
public String index() {
return "index.html";
}
@GetRoute("login")
public String login() {
return "login.html";
}
@PostRoute("login")
public String doLogin(User user, Request request, Response response) {
if (StringKit.isBlank(user.getUsername())) {
request.attribute("error", "用户名不能为空");
return "index.html";
}
if (StringKit.isBlank(user.getPassword())) {
request.attribute("error", "用户名不能为空");
return "login.html";
}
if (!Const.USERNAME.equalsIgnoreCase(user.getUsername()) ||
!Const.PASSWORD.equalsIgnoreCase(user.getPassword())) {
request.attribute("error", "用户名或密码错误");
return "login.html";
}
request.session().attribute(Const.LOGIN_SESSION_KEY, user.getUsername());
response.redirect("/index");
return null;
}
@GetRoute("logout")
public void logout(Session session, Response response) {
session.removeAttribute(Const.LOGIN_SESSION_KEY);
response.redirect("/login");
}
}
代码逻辑也非常简单,登陆成功后将用户名存储在session里,注销后跳转到登陆页面;Blade支持将 username
,password
通过对象的方式传递到后台中,你也可以选择一个参数一个参数的获取。
第三步,编写页面
在 resources
目录下创建一个名为 templates
的目录,我们将模板文件放在这里
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>登陆页面</title>
<!-- Bootstrap core CSS -->
<link href="/webjars/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="/static/css/signin.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<form class="form-signin" method="post" action="/login">
<h2 class="form-signin-heading">来吧客官 :)</h2>
<label for="inputEmail" class="sr-only">邮箱</label>
<input type="email" name="username" class="form-control" placeholder="请输入登陆邮箱" required autofocus>
<label class="sr-only">Password</label>
<input type="password" name="password" class="form-control" placeholder="请输入密码" required/>
<p style="color: red">${error}</p>
<button class="btn btn-lg btn-primary btn-block" type="submit">登 陆</button>
</form>
</div>
</body>
</html>
刚好复习一下前面学习的 webjars
将bootstrap的css引入进来,登陆页面是这个样子:
然后编写一个 index.html 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆成功</title>
</head>
<body>
<h1>${loginuser} 大兄弟,你获得力量了!!</h1>
<a href="/logout">我要注销</a>
</body>
</html>
第四步,拦截未登录
我们不允许未登录的用户访问 index
,那么在blade中最简单的实现方式就是注册一个 before
请求或者实现 webhook
,这里我们简单起见写一个 before
请求完成这个功能,逻辑复杂的时候请使用webhook单独去处理。
Blade.me().before("/*", ((request, response) -> {
String uri = request.uri();
if("/index".equals(uri)){
String username = request.session().attribute(Const.LOGIN_SESSION_KEY);
if (StringKit.isBlank(username)) {
response.redirect("/login");
return;
}
}
}));
判断当访问 /index
的时候session中是否有登陆状态,如果没有则跳转到登陆页面。
public class Const {
public static String USERNAME;
public static String PASSWORD;
public static final String LOGIN_SESSION_KEY = "loginuser";
}
public class User {
private String username;
private String password;
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;
}
}
客官,登陆吧
当我们输入错误的用户名密码,页面会有提示,输入正确后会是这样:
点击 我要注销
后会跳转到登陆页面,本章节的源码在 github。