--- title: 毕业设计(4) tags: - java - ssm - react - ant design - typescript categories: 毕业设计 date: 2022-12-14 12:40:32 summary: 登录实现 --- ## 十、管理登录逻辑后端实现     管理员账号的账号密码从配置文件中读写 ```java @RestController @PropertySource("classpath:config/config.properties") @RequestMapping("/admin") public class AdminController { @Value("${admin.username}") String username; @Value("${admin.password}") String password; @PostMapping("/login") public ResponseEntity>> login(@RequestBody Map params){ String user = params.get("phone"); String pass = params.get("password"); HashMap map = new HashMap<>(); if (user.equals(username) && pass.equals(password)){ map.put("phone",username); map.put("password",password); map.put("type","admin"); String token = Jwt.sign(map); map.remove("password"); map.put("token",token); return ResponseEntity.ok(Resp.Ok(map)); } return ResponseEntity.status(HttpStatus.PAYMENT_REQUIRED).body(Resp.Err(403,null,map)); } } ``` 从 **config.propertie** 文件中中读取管理员的账号密码,然后配置登录的controller类,首先判断账号密码是否正确,正确就调用 **Jwt** 生成登录token,返回token到前端。 鉴权拦截器 在spring mvc的配置文件中配置拦截器,配置除了登陆地址以外全部拦截 ```xml ``` 拦截器类 ```java @PropertySource("classpath:config/config.properties") public class AuthInterceptor implements HandlerInterceptor { @Value("${admin.username}") String username; @Value("${admin.password}") String password; @Resource StudentService studentService; @Resource TeacherService teacherService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String authorization = request.getHeader("Authorization"); if (authorization == null || authorization.equals("")){ response.sendError(401,"the auth fail!"); return false; }else { HashMap map = Jwt.verify(authorization.split(" ")[1], HashMap.class); if (map==null){ throw new MyException("未登录!"); } request.getSession().setAttribute("login_type",map.get("type")); Object type = map.get("type"); if ("admin".equals(type)) { if (map.get("phone").equals(username) && map.get("password").equals(password)) { return true; } else { throw new MyException("未登录!"); } } else if ("student".equals(type)) { Student student = new Student(); student.setPhone((String) map.get("phone")); student.setId((Integer) map.get("id")); Page students = studentService.queryByPage(student, PageRequest.of(0, 100)); return students.getContent().size() >= 1; } else if ("teacher".equals(type)) { Teacher teacher = new Teacher(); teacher.setPhone((String) map.get("phone")); teacher.setId((Integer) map.get("id")); Page teachers = teacherService.queryByPage(teacher, PageRequest.of(0, 100)); return teachers.getContent().size() >= 1; } throw new Exception("权限检测错误!"); } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } } ``` 调用jwt解析前端携带的token,检测账号密码是否正确,如果正确则返回 **true**,否则抛出异常错误。 ## 十一、前端基本配置 项目前端采用 **react+ant design**编写,语言使用 **typescript** ,开发工具使用 **webstorm** 。 首先使用webstorm创建react项目,使用typescript模板,然后添加依赖 ### 添加依赖 ```shell yarn add antd yarn add axios yarn add react-router-dom yarn add http-proxy-middleware -D ``` 因为在项目开发过程中,需要解决跨域的问题,所以我们使用开发依赖 **http-proxy-middleware**,将前端的接口转发到本地开发地址。 ### 解决本地调试跨域 **setupProxy.js** ```javascript const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = function(app) { app.use("/api",createProxyMiddleware({ target: "http://127.0.0.1:8080", changeOrigin: true, pathRewrite:{ "/api":"/" } })) } ``` 配置项目前端路由,在index.tsx中添加 **HashRouter**节点 ### 配置根路由 **index.tsx** ```typescript import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; import {HashRouter} from "react-router-dom"; const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); root.render( ); reportWebVitals(); ``` 在App.tsx中添加基本页面,因为使用类组件开发,类组件中无法使用hooks等回调,所以将App组件使用WithRouter进行包装一下。 ### 配置主页面 **App.tsx** ```typescript import React, {Component} from 'react'; import './App.css'; import { useLocation, useNavigate, useParams, Routes, Route } from "react-router-dom"; import LoginPage from "./pages/LoginPage"; import {PageProps} from "./models/props"; import AdminPage from "./pages/admin/AdminPage"; import TeacherPage from "./pages/teacher/TeacherPage"; import StudentPage from "./pages/student/StudentPage"; import AddTeacher from "./pages/admin/AddTeacher"; function withRouter(Component: any) { function ComponentWithRouterProp(props: any) { let location = useLocation(); let navigate = useNavigate(); let params = useParams(); return ( ); } return ComponentWithRouterProp; } class App extends Component { render() { return <> }/> }> }/> }/> }/> } } export default withRouter(App); ``` ## 十一、前端登录页面实现 首先封装axios,封装axios的接口为工具类 后端返回的json将其封装为 **IResponseData** ### 封装axios **request.ts** ```typescript import axios, {AxiosInstance, AxiosRequestConfig, AxiosResponse} from "axios"; import {message} from "antd"; type TAxiosOption = { baseURL: string; timeout: number; } class Http { service: AxiosInstance; constructor(config:TAxiosOption) { this.service = axios.create(config); this.service.defaults.withCredentials = true this.service.interceptors.request.use( (value)=>{ if (value.headers !== null){ // @ts-ignore value.headers.Authorization = "Bearer "+sessionStorage.getItem("work_token") } return value },()=>{ console.log("请求异常") }) this.service.interceptors.response.use((value:AxiosResponse>)=>{ console.log(value) return value },(error)=>{ console.log(error.response.data.message) if (error.response.data.message !== ""){ message.error(error.response.data.message).then(() => {}) } if (error.response.status === 401){ window.location.hash = "/login" } return error }) } get(url: string, params?: object, _object = {}): Promise>> { return this.service.get(url, { params, ..._object }) } post(url: string, data?: object, _object:AxiosRequestConfig = {}): Promise>> { return this.service.post(url, data, _object) } put(url: string, params?: object, _object = {}): Promise>> { return this.service.put(url, params, _object) } delete(url: string, params?: any, _object = {}): Promise>> { return this.service.delete(url, { params, ..._object }) } } export default Http export interface IResponseData { success: boolean; message?:string; data:T; code: number; error?:string } ``` 封装调用后端api的接口为一个类 ### 封装接口 **api.ts** ```typescript import Http, {IResponseData} from "./request"; import { AdminClass, GetAdminClassResp, GetStudentResp, GetTeacherClassResp, GetTeacherResp, LoginResp, Student, Teacher } from "../models/resp"; let http = new Http({ baseURL: "/", timeout: 30000 }); let base = process.env.REACT_APP_BASE_URL class Api { login = async function(type:string, username: string, password: string) { let data = await http.post(`${base}/${type}/login`,{ "phone": username, "password": password }); return data.data } } export default new Api() ``` 登录页面组件采用Layout进行管理,在header组件中添加页面标题,在content组件中添加Form表单。 ### 登录主页面 ```typescript import {Component} from "react"; import {PageProps} from "../models/props"; import {Button, Checkbox, Form, Input, Layout, Select} from "antd"; import { Col, Row } from 'antd'; import loginImg from "../img/loginnew-img.jpg"; import '../utils/api' import api from "../utils/api"; const { Header, Footer, Content } = Layout; const options = [ { "label": "学生", "value": "student" }, { "label": "老师", "value": "teacher" }, { "label": "家长", "value": "patriarch" }, { "label": "管理员", "value": "admin" } ] class LoginPage extends Component{ onSubmit = (value:any) => { api.login(value.type,value.phone,value.password).then(resp => { if (resp.code === 200){ sessionStorage.setItem("work_token",resp.data.token) this.props.router.navigate(`/${value.type}`) } }) } render() { return (<>

分 层 教 学 作 业 收 集 系 统

图片

登 录

记住密码