欢迎光临
我们一直在努力

基于 vue-element-admin 前后端分离项目的完整调用流程

1. 项目整体架构

前端 (Vue.js + Element UI) 后端 (Spring Boot/Node.js等)
┌─────────────────┐ ┌──────────────────┐
│ Vue Router │◄───────►│ Controller │
│ Vuex Store │◄───────►│ Service │
│ Axios Request │◄───────►│ DAO/Mapper │
│ Components │ │ Database │
└─────────────────┘ └──────────────────┘

2. 用户登录流程

前端流程

// 1. 用户在登录页面输入用户名密码
// views/login/index.vue
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.$store.dispatch('user/login', this.loginForm)
.then(() => {
this.$router.push({ path: this.redirect || '/' })
this.loading = false
})
.catch(() => {
this.loading = false
})
}
})
}

// 2. 调用 store action
// store/modules/user.js
login({ commit }, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password }).then(response => {
const { data } = response
commit('SET_TOKEN', data.token)
setToken(data.token) // 存储到 Cookie
resolve()
}).catch(error => {
reject(error)
})
})
}

// 3. API 调用
// api/user.js
export function login(data) {
return request({
url: '/user/login',
method: 'post',
data
})
}

后端流程 (以 Spring Boot 为例)

// 1. Controller 接收请求
@RestController
@RequestMapping("/user")
public class UserController {

@Autowired
private UserService userService;

@PostMapping("/login")
public Result login(@RequestBody LoginRequest loginRequest) {
String token = userService.login(loginRequest);
return Result.success().put("token", token);
}
}

// 2. Service 处理业务逻辑
@Service
public class UserServiceImpl implements UserService {

@Autowired
private UserMapper userMapper;

@Override
public String login(LoginRequest loginRequest) {
// 验证用户名密码
User user = userMapper.selectByUsername(loginRequest.getUsername());
if (user == null || !passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())) {
throw new RuntimeException("用户名或密码错误");
}

// 生成 JWT Token
String token = JwtUtils.generateToken(user.getId(), user.getUsername());
return token;
}
}

3. 带 Token 的业务请求流程

前端请求流程

// 1. 页面组件发起请求
// views/dashboard/index.vue
async getList() {
this.listLoading = true
try {
const response = await getList(this.listQuery)
this.list = response.data.items
} catch (error) {
console.error(error)
} finally {
this.listLoading = false
}
}

// 2. API 定义
// api/table.js
export function getList(params) {
return request({
url: '/table/list',
method: 'get',
params
})
}

// 3. Axios 拦截器自动添加 Token
// utils/request.js
service.interceptors.request.use(config => {
if (store.getters.token) {
config.headers['Authorization'] = `Bearer ${getToken()}`
}
return config
})

后端处理流程

// 1. Controller 接收带 Token 的请求
@RestController
@RequestMapping("/table")
public class TableController {

@Autowired
private TableService tableService;

@GetMapping("/list")
public Result list(@RequestParam Map<String, Object> params) {
PageUtils page = tableService.queryPage(params);
return Result.success().put("data", page);
}
}

// 2. 拦截器验证 Token
@Component
public class JwtInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (StringUtils.isBlank(token)) {
throw new UnauthorizedException("未提供认证令牌");
}

// 验证 Token
Claims claims = JwtUtils.parseToken(token.replace("Bearer ", ""));
Long userId = claims.get("userId", Long.class);

// 将用户信息存入 ThreadLocal
UserContext.setUserId(userId);
return true;
}
}

// 3. Service 执行业务逻辑
@Service
public class TableServiceImpl implements TableService {

@Autowired
private TableMapper tableMapper;

@Override
public PageUtils queryPage(Map<String, Object> params) {
// 从 ThreadLocal 获取用户 ID
Long userId = UserContext.getUserId();

// 查询数据库
Query query = new Query(params);
List<TableEntity> list = tableMapper.queryPage(query);
int total = tableMapper.queryTotal(query);

PageUtils page = new PageUtils(list, total, query.getLimit(), query.getPage());
return page;
}
}

4. 完整的时序图

用户操作 → Vue组件 → Vuex Action → API Service → Axios → 网络传输
→ 后端Controller → Service → DAO → 数据库

响应数据 ← 后端Response ← 业务逻辑处理 ← 数据查询 ← 数据库结果

Vue组件更新 ← Vuex Mutation ← API Response ← Axios响应 ← 网络传输

5. 错误处理流程

前端错误处理

// utils/request.js 响应拦截器
service.interceptors.response.use(
response => {
const res = response.data

if (res.code !== 20000) {
Message({
message: res.message || 'Error',
type: 'error',
duration: 5 * 1000
})

// Token 过期处理
if (res.code === 50014) {
MessageBox.confirm('Token已过期,请重新登录', '确认退出', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
}
return Promise.reject(new Error(res.message || 'Error'))
} else {
return res
}
},
error => {
// HTTP 状态码错误处理
if (error.response.status === 401) {
// 未授权,跳转到登录页
store.dispatch('user/resetToken').then(() => {
location.reload()
})
}
Message.error(error.message)
return Promise.reject(error)
}
)

后端统一响应格式

// 统一响应对象
@Data
public class Result<T> implements Serializable {
private static final long serialVersionUID = 1L;

private Integer code;
private String msg;
private T data;

public static <T> Result<T> success() {
return success(null);
}

public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(20000);
result.setMsg("成功");
result.setData(data);
return result;
}

public static <T> Result<T> error(String msg) {
return error(50000, msg);
}

public static <T> Result<T> error(Integer code, String msg) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMsg(msg);
return result;
}
}

6. 权限控制流程

前端路由守卫

// permission.js
router.beforeEach(async(to, from, next) => {
const hasToken = getToken()

if (hasToken) {
if (to.path === '/login') {
next({ path: '/' })
} else {
const hasRoles = store.getters.roles && store.getters.roles.length > 0
if (hasRoles) {
next()
} else {
try {
const { roles } = await store.dispatch('user/getInfo')

// 根据角色生成可访问路由
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
router.addRoutes(accessRoutes)

next({ …to, replace: true })
} catch (error) {
await store.dispatch('user/resetToken')
next(`/login?redirect=${to.path}`)
}
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
next(`/login?redirect=${to.path}`)
}
}
})

后端权限验证

// 方法级别的权限注解
@RestController
@RequestMapping("/system/user")
public class SysUserController {

@RequiresPermissions("system:user:list")
@GetMapping("/list")
public Result list(@RequestParam Map<String, Object> params) {
PageUtils page = userService.queryPage(params);
return Result.success().put("data", page);
}

@RequiresPermissions("system:user:add")
@PostMapping("/save")
public Result save(@RequestBody User user) {
userService.save(user);
return Result.success();
}
}

7. 文件上传流程

前端上传

// 使用 el-upload 组件
<el-upload
:action="uploadUrl"
:headers="headers"
:show-file-list="false"
:on-success="handleSuccess"
>
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>

// 设置请求头
computed: {
headers() {
return {
'Authorization': 'Bearer ' + getToken()
}
}
}

后端处理

@RestController
@RequestMapping("/common/upload")
public class CommonController {

@PostMapping("/file")
public Result uploadFile(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return Result.error("上传文件不能为空");
}

try {
// 保存文件
String fileName = fileService.upload(file);
Map<String, Object> data = new HashMap<>();
data.put("fileName", fileName);
data.put("url", fileService.getFileUrl(fileName));
return Result.success().put("data", data);
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
}

这个完整的流程展示了从用户操作到最终数据显示的全过程,包括认证、授权、业务逻辑处理和错误处理等各个环节。

赞(0)
未经允许不得转载:171主机测评 » 基于 vue-element-admin 前后端分离项目的完整调用流程
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址