继续编写用户服务;增添基础信息服务;增强异常管理,美化相关界面;

This commit is contained in:
Saturneric 2020-02-18 02:25:24 +08:00
parent a74da9805e
commit d64a4aca62
24 changed files with 327 additions and 129 deletions

View File

@ -34,8 +34,11 @@ public class DataModelRepositorySearcher {
}
public <T> T getDataModelRepositoryInstance() {
// 确保可以引用
if(isPresent()) {
return (T) springUtil.getBean(repositoryClass);
@SuppressWarnings("unchecked")
T repository = (T) springUtil.getBean(repositoryClass);
return repository;
}
return null;
}

View File

@ -10,7 +10,7 @@ import java.util.ArrayList;
import java.util.Collection;
/**
* 查找特定的Model以创建相应的操作表单(多例模式)
* 根据子系统及名称查找特定的Data Model
*/
@Data
@Component

View File

@ -13,6 +13,7 @@ import org.springframework.web.context.request.WebRequest;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller
@ -30,13 +31,12 @@ public class ASEErrorController implements ErrorController {
model.addAttribute("exception_name", exception.getClass().getName());
model.addAttribute("exception_message", exception.getMessage());
List<String> stack_infos = new ArrayList<>();
for(StackTraceElement element : exception.getStackTrace()){
String s = element.toString();
stack_infos.add(s);
}
model.addAttribute("error_stack", stack_infos);
model.addAttribute("exception_date",new Date());
return "error";
}

View File

@ -35,6 +35,8 @@ public class DataManagerController {
if(!dataModelRepositorySearcher.isPresent()){
throw new RuntimeException("Data Model Repository Not Found");
}
Map<String, Object> data;
return "query";
}
}

View File

@ -0,0 +1,17 @@
package com.codesdream.ase.exception;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class UserInformationIllegalException extends RuntimeException {
String username;
public UserInformationIllegalException(String username){
super();
this.username = username;
}
}

View File

@ -0,0 +1,17 @@
package com.codesdream.ase.exception;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class UserNotFoundException extends RuntimeException {
Integer id;
String username;
public UserNotFoundException(Integer id, String username){
super();
this.id = id;
this.username = username;
}
}

View File

@ -0,0 +1,16 @@
package com.codesdream.ase.exception;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class UsernameAlreadyExistException extends RuntimeException {
String username;
public UsernameAlreadyExistException(String username){
super();
this.username = username;
}
}

View File

@ -5,7 +5,7 @@ import lombok.Data;
import javax.persistence.*;
/**
* 考生类别
* 考生类别基本信息
*/
@Data
@Entity

View File

@ -4,6 +4,9 @@ import lombok.Data;
import javax.persistence.*;
/**
* 民族基本信息
*/
@Data
@Entity
@Table(name = "base_ethnic")

View File

@ -4,6 +4,9 @@ import lombok.Data;
import javax.persistence.*;
/**
* 专业基本信息
*/
@Data
@Entity
@Table(name = "base_major")

View File

@ -5,7 +5,7 @@ import lombok.Data;
import javax.persistence.*;
/**
* 政治面貌
* 政治面貌基本信息
*/
@Data
@Entity

View File

@ -1,8 +1,6 @@
package com.codesdream.ase.model.permission;
import com.codesdream.ase.model.information.BaseAdministrativeDivision;
import com.codesdream.ase.model.information.BaseCollege;
import com.codesdream.ase.model.information.BaseMajor;
import com.codesdream.ase.model.information.*;
import lombok.Data;
import javax.persistence.*;
@ -19,20 +17,28 @@ public class UserDetail {
private int id;
// 所属地区
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@OneToOne(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
private BaseAdministrativeDivision baseAdministrativeDivision;
// 所属学院
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@OneToOne(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
private BaseCollege baseCollege;
// 所属专业
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@OneToOne(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
private BaseMajor baseMajor;
// 民族
@OneToOne(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
private BaseEthnic baseEthnic;
// 政治面貌
@OneToOne(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
private BasePoliticalStatus basePoliticalStatus;
// 真实姓名
private String realName;
private String realName = "";
// 在校状态
private boolean atSchool;
private boolean atSchool = false;
}

View File

@ -0,0 +1,12 @@
package com.codesdream.ase.repository.information;
import com.codesdream.ase.model.information.BaseAdministrativeDivision;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface BaseAdministrativeDivisionRepository extends CrudRepository<BaseAdministrativeDivision, Integer> {
Optional<BaseAdministrativeDivision> findByName(String name);
}

View File

@ -0,0 +1,12 @@
package com.codesdream.ase.repository.information;
import com.codesdream.ase.model.information.BaseCandidateCategory;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface BaseCandidateCategoryRepository extends CrudRepository<BaseCandidateCategory, Integer> {
Optional<BaseCandidateCategory> findByName(String name);
}

View File

@ -0,0 +1,13 @@
package com.codesdream.ase.repository.information;
import com.codesdream.ase.model.information.BaseCollege;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface BaseCollegeRepository extends CrudRepository<BaseCollege, Integer> {
Optional<BaseCollege> findByName(String name);
Optional<BaseCollege> findByNumber(Integer number);
}

View File

@ -0,0 +1,12 @@
package com.codesdream.ase.repository.information;
import com.codesdream.ase.model.information.BaseEthnic;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface BaseEthnicRepository extends CrudRepository<BaseEthnic, Integer> {
Optional<BaseEthnic> findByName(String name);
}

View File

@ -0,0 +1,12 @@
package com.codesdream.ase.repository.information;
import com.codesdream.ase.model.information.BaseMajor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface BaseMajorRepository extends CrudRepository<BaseMajor, Integer> {
Optional<BaseMajor> findByName(String name);
}

View File

@ -0,0 +1,10 @@
package com.codesdream.ase.repository.information;
import com.codesdream.ase.model.information.BasePoliticalStatus;
import org.springframework.data.repository.CrudRepository;
import java.util.Optional;
public interface BasePoliticalStatusRepository extends CrudRepository<BasePoliticalStatus, Integer> {
Optional<BasePoliticalStatus> findByName(String name);
}

View File

@ -0,0 +1,5 @@
package com.codesdream.ase.service;
public interface IBaseInformationService {
boolean checkAdministrativeDivision(String name);
}

View File

@ -1,6 +1,7 @@
package com.codesdream.ase.service;
import com.codesdream.ase.model.permission.User;
import javafx.util.Pair;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
@ -16,20 +17,28 @@ public interface IUserService {
List<User> findAll();
Optional<User> findUserById(int id);
User findUserByUsername(String username);
public Pair<Boolean, User> checkIfUserExists(String username);
// 获得用户所有的权限角色
Collection<? extends GrantedAuthority> getUserAuthorities(User user);
// 更新用户的密码
void updatePassword(User user, String password);
// 生成随机用户名
// 根据学号生成随机用户名
void generateRandomUsernameByStudentID(User user, String id);
// 注册用户
User save(User user);
// 更新用户信息
User update(User user);
// 删除用户
void delete(User user);
}

View File

@ -3,8 +3,12 @@ package com.codesdream.ase.service;
import com.codesdream.ase.component.permission.ASEPasswordEncoder;
import com.codesdream.ase.component.permission.ASEUsernameEncoder;
import com.codesdream.ase.component.permission.UserRolesListGenerator;
import com.codesdream.ase.exception.UserInformationIllegalException;
import com.codesdream.ase.exception.UserNotFoundException;
import com.codesdream.ase.exception.UsernameAlreadyExistException;
import com.codesdream.ase.model.permission.User;
import com.codesdream.ase.repository.permission.UserRepository;
import javafx.util.Pair;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@ -41,10 +45,16 @@ public class UserService implements IUserService {
@Override
public User findUserByUsername(String username) {
Optional<User> user = userRepository.findByUsername(username);
if(!user.isPresent()) throw new UsernameNotFoundException("User Not Found");
if(!user.isPresent()) throw new UsernameNotFoundException(username);
return user.get();
}
@Override
public Pair<Boolean, User> checkIfUserExists(String username){
Optional<User> user = userRepository.findByUsername(username);
return user.map(value -> new Pair<>(true, value)).orElseGet(() -> new Pair<>(false, null));
}
@Override
public Collection<? extends GrantedAuthority> getUserAuthorities(User user) {
return userRolesListGenerator.generateRoles(user);
@ -66,23 +76,43 @@ public class UserService implements IUserService {
public User save(User user) {
// 查找用户名是否已经被注册
if(userRepository.findByUsername(user.getUsername()).isPresent())
throw new RuntimeException("Username Already Exists");
throw new UsernameAlreadyExistException(user.getUsername());
// 用户信息一般性规范检查
if(user.getUserAuth().getUserAnswer().length() > 255
|| user.getUserAuth().getUserQuestion().length() > 255
|| user.getUserAuth().getStudentID().length() > 24
|| user.getUserAuth().getMail().length() > 64
|| user.getUserDetail().getRealName().length() > 12)
throw new UserInformationIllegalException(user.getUsername());
// 强制以哈希值(sha256)保存密码
user.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepository.save(user);
}
@Override
public User update(User user) {
if(!userRepository.findByUsername(user.getUsername()).isPresent())
throw new RuntimeException("Username Already Exists");
// 执行前检查
if(!userRepository.findById(user.getId()).isPresent())
throw new UserNotFoundException(user.getId(), user.getUsername());
return userRepository.save(user);
}
@Override
public void delete(User user) {
// 执行前检查
if(!userRepository.findById(user.getId()).isPresent())
throw new UserNotFoundException(user.getId(), user.getUsername());
userRepository.delete(user);
}
// 获得一个默认初始化的用户对象
@Override
public User getDefaultUser() {
return new User();
}
}

View File

@ -1,74 +1,71 @@
package com.codesdream.ase.test;
import com.codesdream.ase.model.permission.FunctionalPermissionContainer;
import com.codesdream.ase.model.permission.Tag;
import com.codesdream.ase.model.permission.User;
import com.codesdream.ase.repository.permission.UserRepository;
import static org.junit.Assert.*;
import com.codesdream.ase.service.UserService;
import com.sun.org.apache.xpath.internal.operations.Bool;
import javafx.util.Pair;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.HashSet;
import javax.annotation.Resource;
/**
* 用户基本表单元测试
* 用于测试数据库与DAO层交互是否通畅
*/
@DataJpaTest
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserTest {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository userRepository;
@Resource
private UserService userService;
/**
* 基本存储与查询测试
*/
@Test
public void UserBaseTest_1(){
User user = new User("Tim", "123456");
userRepository.save(user);
assertTrue(userRepository.findByUsername("Tim").isPresent());
assertFalse(userRepository.findByUsername("Tom").isPresent());
user = userRepository.findByUsername("Tim").get();
// 查找数据库中是否有重复项
Pair<Boolean, User> checker = userService.checkIfUserExists("Tim");
if(checker.getKey()){
userService.delete(checker.getValue());
}
User user = userService.getDefaultUser();
user.setUsername("Tim");
user.setPassword("123456");
user.getUserAuth().setStudentID("2018303026");
user.getUserAuth().setMail("937447984@qq.com");
user.getUserAuth().setUserQuestion("Your favourite animal?");
user.getUserAuth().setUserAnswer("Cat");
user.getUserDetail().setAtSchool(true);
userService.save(user);
user = userService.findUserByUsername("Tim");
assertEquals(user.getUsername(), "Tim");
assertEquals(user.getPassword(), "123456");
assertEquals(user.getPassword(),
"8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92");
// 检查账号状态
assertTrue(user.isEnabled());
assertFalse(user.isDeleted());
assertTrue(user.isAccountNonExpired());
assertTrue(user.isAccountNonLocked());
assertTrue(user.isCredentialsNonExpired());
assertEquals(user.getUserAuth().getStudentID(), "2018303026");
assertEquals(user.getUserAuth().getMail(), "937447984@qq.com");
assertEquals(user.getUserAuth().getUserQuestion(), "Your favourite animal?");
assertEquals(user.getUserAuth().getUserAnswer(), "Cat");
}
@Test
public void UserBaseTest_2(){
// 用户
User user = new User("Pat", "123456");
// 标签
Tag tag = new Tag("学生","普通学生");
// 功能性权限容器
FunctionalPermissionContainer functionalPermissionContainer =
new FunctionalPermissionContainer("基本用户权限", "基本的用户权限");
// 添加为标签功能性权限容器
HashSet<FunctionalPermissionContainer> functionalPermissionContainers = new HashSet<>();
functionalPermissionContainers.add(functionalPermissionContainer);
// 等待添加
// 为用户添加标签
HashSet<Tag> tags = new HashSet<>();
tags.add(tag);
user.setTags(tags);
userRepository.save(user);
User user = userService.findUserByUsername("Tim");

View File

@ -8,83 +8,89 @@
</head>
<body>
<div class="logo-header" data-background-color="blue" style="width:100%">
<h1><font color="#FFFFFF">Error</font></h1>
</div>
<div class="wrapper">
<div class="main-header">
<nav class="navbar navbar-header navbar-expand-lg" data-background-color="blue2">
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<h2>
检测到异常发生
</h2>
<p>
<strong><strong>当服务器端程序内部某个模块抛出异常时,该界面就会被显示。此次异常的简要信息已被异常管理子系统收集并概括如下表:</strong></strong>
</p>
<table class="table table-bordered">
<h1 style="color: white">Error Occurred</h1>
</div>
</nav>
</div>
<div class="main-panel">
<div class="content">
<div class="page-inner">
<div class="page-header">
<h4 class="page-title"><div class="fa fa-surprise"></div>&nbsp; 异常被抛出 (Exception Thrown)</h4>
</div>
<div class="row">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h4 class="card-title"><div class="fa fa-cogs"></div> &nbsp; 概要信息</h4>
</div>
<div class="card-body">
<div class="card-sub">
此次异常的简要信息已被异常管理子系统收集并概括如下表
</div>
<table class="table table-bordered table-head-bg-info table-bordered-bd-info mt-8">
<thead>
<tr>
<th>
编号
</th>
<th>
信息项
</th>
<th>
</th>
<th scope="col">#</th>
<th scope="col">信息项</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr>
<td>
0
</td>
<td>
服务器返回HTTP状态
</td>
<td th:text="${http_status}">
</td>
<td>0 </td>
<td>HTTP状态</td>
<td class="text-primary" th:text="${http_status}"></td>
</tr>
<tr>
<td>
1
</td>
<td>
抛出的异常类型
</td>
<td th:text="${exception_name}">
</td>
<td>1</td>
<td>异常类型</td>
<td class="text-primary" th:text="${exception_name}"></td>
</tr>
<tr>
<td>
2
</td>
<td>
异常附带消息
</td>
<td th:text="${exception_message}">
</td>
<td>2</td>
<td>附带消息</td>
<td class="text-primary" th:text="${exception_message}"></td>
</tr>
<tr>
<td>2</td>
<td>附带消息</td>
<td class="text-primary" th:text="${#dates.format(exception_date, 'yyyy-MM-dd HH:mm:ss')}"></td>
</tr>
</tbody>
</table>
<h3>
运行栈相关信息补充
</h3>
<p th:each="line : ${error_stack}">
<span th:text="${line}"></span>
</p>
</div>
</div>
<div class="card">
<div class="card-header">
<h1 class="card-title"><div class="fa fa-bug"></div> &nbsp; 运行栈相关信息</h1>
</div>
<div class="card-body">
<ol class="activity-feed">
<li class="feed-item" th:each="line : ${error_stack}">
<span class="text" th:text="${line}"></span>
</li>
</ol>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -8,10 +8,23 @@
</head>
<body>
<div class="logo-header" data-background-color="blue" style="width:100%">
<h1><font color="#FFFFFF">404 Not Found</font></h1>
<div class="wrapper">
<div class="main-header">
<nav class="navbar navbar-header navbar-expand-lg" data-background-color="blue2">
<div class="container-fluid">
<h1 style="color: white">Page Not Found</h1>
</div>
</nav>
</div>
<div class="main-panel">
<div class="content">
<div class="col-md-8">
<div class="card"><img th:src="@{/assets/img/404.jpg}" /></div>
</div>
</div>
</div>
</div>
</body>