前面两篇博客对Simple OKR项目的背景和开发环境的搭建进行了简单介绍。从这篇文章开始进入项目开发过程中遇到的一些问题和知识点的记录。在项目开发过程中会以功能点的形式进行介绍和记录,对于相对比较简单的功能点会在一篇博文当中进行记录,对于某些比较复杂的功能可能会分成几篇博文进行介绍。
这篇博文当中我们将建立一个简单的登录、注册页面,并实现简单的后端逻辑。
目标博主在开发过程当中喜欢先设置一个目标,然后在开发过程当中参照既定的目标开展相应的工作,否则蒙头写代码写到最后都不知道自己到底要干什么。
功能目标- 实现登录、注册页面
- 能够向后端发起Http请求
- 后端能够实现登录、等出功能
- 后端实现用户登录信息的储存
这次需要实现的功能相对比较简单,我们也来简单梳理一下完成上述工作过程中本文会简单介绍的知识点。
知识点整理- HTTP请求
- 什么跨域
- 数据持久化
- Spring控制器和RESTful API的编写
废话不多说,直接开始代码实验,在一些操作过程当中给再穿插一些简单的理论知识介绍。
首先确保根据之前的教程Simple OKR项目简记 (二):环境搭建完成基本开发环境的配置。本次实验需要用到文中所述的前后端开发环境。
首先我们打开之前创建的Vue 3的app工程目录安装element-plus这个包提供element-ui相关的组件
> yarn add element-plus登录窗体关键代码
在views文件夹下面添加一个新的vue源代码文件Login.vue作为登录页面。
Simple OKRStill haven't an account yet? Register one --> Agree to simple app end user license Login
然后为了能够让这个页面能够被访问到,我们需要修改一下项目中的路由配置
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
import Home from "../views/Home.vue";
const routes: Array = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/about",
name: "about",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import( "../views/about.vue"),
},
{
path: "/login",
name: "Login",
component: () =>
import("../views/Login.vue")
}
];
const router = createRouter({
history: createWebHistory(process.env.base_URL),
routes,
});
export default router;
这里可以看到Home是在代码的头部直接显式引入的,而about和login组件则是在router的规则当中引用的,这样引入的界面会在用户访问对应的url时才会被加载。
如果项目配置和代码均是正确的话,程序运行起来后的效果如下:
到这里前端的工作先告一段落,先把工作的重心转向后端RESTful API的开发。
RESTFul API的搭建如果读者跟着前一篇博文一起配置好了Spring Boot的项目应该已经得到了一个最基本的Spring的项目结构包含pom配置文件和SpringApplication的java源代码文件。现在我们就在这个项目的基础上添砖加瓦构建一个比较通用的Spring Boot后端项目包结构。
okr
├─config // 存放配置
├─controller // api控制器
├─dao // 数据持久层
├─dto // 数据传输对象
├─entity // 数据模型
├─service // 功能服务
│ └─impl // 服务的实现
├─task // 后台任务
└─utils // 工具
我们先在项目当中添加一个用户控制器UserController.java
package simple.okr.controller;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import simple.okr.dto.UserLoginDTO;
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/greet/{username}")
public ResponseEntity Greet(@PathVariable String username)
{
return ResponseEntity.ok("Welcome " + username);
}
@PostMapping("login")
public ResponseEntity
在上面的代码中提供了两个API分别用于演示@PathVariable注解和@RequestBody注解的具体使用。项目运行以后发送HTTP请求就会收到响应了。
首先我们来看一下如果跑不起来的情况,首先当然还得添加一个UserLoginDTO类,否则肯定是不能运行的。
如果通过各位小伙伴的IDE运行项目得到了如下提示:
那么恭喜你,默认的Tomcat的8080端口被占用了。有两种解决方案:
- 干掉占用8080端口的那个货
- 换个端口
有的同学说,我的8080端口有其他作用,又或者说占用8080端口的那货比较头铁,只能选择第二种方案。那么问题来了,怎么换一个端口呢?
此时我们可以观察一下,resource文件夹下面有一个appliation.properties文件作为Spring应用程序的配置文件。博主比较习惯用yml格式的配置文件,所以第一时间就会把后缀名properties修改成yml。
我们在配置文件里添加如下内容,将端口改为8888:
server:
port: 8888
如果符合预期的话,那么程序就可以正常运行了。如果还有运行不起来的小伙伴,请在评论区留言。
那么我们来试一下这两个接口的功能是否工作正常:
### Get request to greet GET http://localhost:8888/user/greet/example HTTP/1.1
通过发送GET请求,我们会收到服务器的响应是这样的
HTTP/1.1 200 Content-Type: text/plain;charset=UTF-8 Content-Length: 15 Date: Thu, 04 Nov 2021 13:09:46 GMT Connection: close Welcome example
结合上述的Java代码,经过简单的推断可以发现服务端总是输出greet/后面的参数作为username的值进行输出。
而发送如下的POST请求给服务器则会增加一个简单的用户名和密码检查功能
POST http://localhost:8888/user/login HTTP/1.1
User-Agent: vscode-restclient
Content-Type: application/json
{
"username": "example",
"password": "example"
}
如果发送的请求内容中用户名和密码均与后端代码中的字符串匹配得到输出和GET请求一样。我们任意修改用户名或者密码,服务器则会返回badRequest 400代码。
HTTP/1.1 400 Content-Length: 0 Date: Thu, 04 Nov 2021 13:17:16 GMT Connection: close
实验进行到这里,有的同学就要有问题了,我的controller跟Application类好像也没有什么直接的显式调用关系。这些疑问博主在刚学习的时候也出现过很久,别着急,我们先把登录这个功能简单的实现完。具体SpringApplication是怎么运行的,请听博主下回博文分解。
Vue通过axios发送http请求接下来我们要做得就是获取到表单里的用户输入,然后发送HTTP请求。
在Simple OKR这个项目里选用了axios作为异步HTTP请求的工具包。
yarn add axios
然后我们先创建一个axios的对象,并进行一些全局配置,后续的请求都基于这个对象。这么做的好处是可以免去很多重复的配置。
import axios from "axios";
import { ElMessage } from "element-plus";
const service = axios.create({
// define the service base url
baseURL: process.env.VUE_APP_base_API,
// timeout
timeout: 5000,
headers: {'Content-Type': 'application/json;charset=utf-8'}
})
console.log(process.env.VUE_APP_base_API);
let loading:any;
let requestCount:number = 0;
// Request Interceptor
service.interceptors.request.use(config => {
return config
}, error => {
console.log(error)
Promise.reject(error)
})
// Response Interceptor
service.interceptors.response.use(res => {
const code = res.status || 200;
console.log(code)
if(code == 200){
return Promise.resolve(res.data)
}else{
ElMessage.error('error request')
return Promise.reject(res.data)
}
},
error => {
console.log(error)
return Promise.reject(error)
}
)
export default service;
接下来我们要做的是设置利用这个request对象发起特定的HTTP请求,我们再对登录这个动作封装一个专门处理用户请求的类
import request from "@/utils/request";
class UserApi {
public async Login(username: string, password: string) : Promise
{
let isLogin = true;
const res = await request.post('/user/login',
{
"username" : username,
"password" : password
}).then(res => {
console.log(res)
isLogin = true
}).catch(err => {
console.log(err)
isLogin = false
})
return isLogin
}
}
export const userApi = new UserApi;
接下来回到我们的Login.vue文件当中,引入userApi这个对象,并且在login方法进行调用
login() : void {
console.log('Login clicked.')
const waitingMessage = ElMessage({
message: 'Login ...',
})
const isTrue = userApi.Login(this.loginForm.username, this.loginForm.password)
isTrue.then( val => {
waitingMessage.close()
if (val) {
ElMessage({
message: 'Welcome, ' + this.loginForm.username,
type: 'success'
})
} else
{
ElMessage({
message: 'Error, Please retry ',
type: 'error'
})
}
})
}
如果一切正常,前后端开发服务器程序都运行起来后,输入登录信息我们就能看到下面两张图的效果:
但是大概率下很多同学都是不成功的,打开浏览器开发者程序的控制台可以看到类似这样的场景
很多同学肯定会说,What's the ... CORS,请自行百度或者查看其他博客,本文限于篇幅不再赘述
那博主是怎么能够成功运行的呢,我们来简单配置一下解决这个问题,在源代码目录下新建一个vue.config.js配置文件写入下面的内容,解决这个问题的核心在devServer这个配置
module.exports = {
lintOnSave: false,
configureWebpack: {
devtool: 'source-map'
},
devServer: {
// proxy for dev server
open: false,
host: 'localhost',
port: 8082,
https: false,
proxy: {
'/api': {
target: process.env.VUE_APP_API_SERVER, // backend server
ws: true,
changOrigin: true, // allow cors
pathRewrite: {
'^/api': ''// rewrite to VUE_APP_API_SERVER/
}
}
}
},
}
重新运行下webpack开发服务器,应该就能成功实现demo的功能了。
小结这篇博文到这里就差不多结束了,我们来简单总结一下博文实现的内容:
- 前端的登录界面
- 前端能够发起HTTP请求进行接口调用
- 后端HTTP请求的响应
- 简单的登录功能
下一篇博文我们将把重心放到后端部分,着重介绍如何实现一个相对完善的用户鉴权功能。
项目更新地址:mrchipset/simple-okr-web.git



