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

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() { public <T> T getDataModelRepositoryInstance() {
// 确保可以引用
if(isPresent()) { if(isPresent()) {
return (T) springUtil.getBean(repositoryClass); @SuppressWarnings("unchecked")
T repository = (T) springUtil.getBean(repositoryClass);
return repository;
} }
return null; return null;
} }

View File

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

View File

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

View File

@ -35,6 +35,8 @@ public class DataManagerController {
if(!dataModelRepositorySearcher.isPresent()){ if(!dataModelRepositorySearcher.isPresent()){
throw new RuntimeException("Data Model Repository Not Found"); throw new RuntimeException("Data Model Repository Not Found");
} }
Map<String, Object> data;
return "query"; 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.*; import javax.persistence.*;
/** /**
* 考生类别 * 考生类别基本信息
*/ */
@Data @Data
@Entity @Entity

View File

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

View File

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

View File

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

View File

@ -1,8 +1,6 @@
package com.codesdream.ase.model.permission; package com.codesdream.ase.model.permission;
import com.codesdream.ase.model.information.BaseAdministrativeDivision; import com.codesdream.ase.model.information.*;
import com.codesdream.ase.model.information.BaseCollege;
import com.codesdream.ase.model.information.BaseMajor;
import lombok.Data; import lombok.Data;
import javax.persistence.*; import javax.persistence.*;
@ -19,20 +17,28 @@ public class UserDetail {
private int id; private int id;
// 所属地区 // 所属地区
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @OneToOne(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
private BaseAdministrativeDivision baseAdministrativeDivision; private BaseAdministrativeDivision baseAdministrativeDivision;
// 所属学院 // 所属学院
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @OneToOne(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
private BaseCollege baseCollege; private BaseCollege baseCollege;
// 所属专业 // 所属专业
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @OneToOne(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
private BaseMajor baseMajor; 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; package com.codesdream.ase.service;
import com.codesdream.ase.model.permission.User; import com.codesdream.ase.model.permission.User;
import javafx.util.Pair;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import java.util.Collection; import java.util.Collection;
@ -16,20 +17,28 @@ public interface IUserService {
List<User> findAll(); List<User> findAll();
Optional<User> findUserById(int id); Optional<User> findUserById(int id);
User findUserByUsername(String username); User findUserByUsername(String username);
public Pair<Boolean, User> checkIfUserExists(String username);
// 获得用户所有的权限角色 // 获得用户所有的权限角色
Collection<? extends GrantedAuthority> getUserAuthorities(User user); Collection<? extends GrantedAuthority> getUserAuthorities(User user);
// 更新用户的密码 // 更新用户的密码
void updatePassword(User user, String password); void updatePassword(User user, String password);
// 生成随机用户名 // 根据学号生成随机用户名
void generateRandomUsernameByStudentID(User user, String id); void generateRandomUsernameByStudentID(User user, String id);
// 注册用户
User save(User user); User save(User user);
// 更新用户信息
User update(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.ASEPasswordEncoder;
import com.codesdream.ase.component.permission.ASEUsernameEncoder; import com.codesdream.ase.component.permission.ASEUsernameEncoder;
import com.codesdream.ase.component.permission.UserRolesListGenerator; 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.model.permission.User;
import com.codesdream.ase.repository.permission.UserRepository; import com.codesdream.ase.repository.permission.UserRepository;
import javafx.util.Pair;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -41,10 +45,16 @@ public class UserService implements IUserService {
@Override @Override
public User findUserByUsername(String username) { public User findUserByUsername(String username) {
Optional<User> user = userRepository.findByUsername(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(); 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 @Override
public Collection<? extends GrantedAuthority> getUserAuthorities(User user) { public Collection<? extends GrantedAuthority> getUserAuthorities(User user) {
return userRolesListGenerator.generateRoles(user); return userRolesListGenerator.generateRoles(user);
@ -66,23 +76,43 @@ public class UserService implements IUserService {
public User save(User user) { public User save(User user) {
// 查找用户名是否已经被注册 // 查找用户名是否已经被注册
if(userRepository.findByUsername(user.getUsername()).isPresent()) 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())); user.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepository.save(user); return userRepository.save(user);
} }
@Override @Override
public User update(User user) { 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); 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 @Override
public User getDefaultUser() { public User getDefaultUser() {
return new User(); return new User();
} }
} }

View File

@ -1,74 +1,71 @@
package com.codesdream.ase.test; 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.model.permission.User;
import com.codesdream.ase.repository.permission.UserRepository;
import static org.junit.Assert.*; 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.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import java.util.HashSet; import javax.annotation.Resource;
/** /**
* 用户基本表单元测试 * 用户基本表单元测试
* 用于测试数据库与DAO层交互是否通畅 * 用于测试数据库与DAO层交互是否通畅
*/ */
@DataJpaTest
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest
public class UserTest { public class UserTest {
@Autowired @Resource
private TestEntityManager entityManager; private UserService userService;
@Autowired
private UserRepository userRepository;
/** /**
* 基本存储与查询测试 * 基本存储与查询测试
*/ */
@Test @Test
public void UserBaseTest_1(){ public void UserBaseTest_1(){
User user = new User("Tim", "123456"); // 查找数据库中是否有重复项
userRepository.save(user); Pair<Boolean, User> checker = userService.checkIfUserExists("Tim");
assertTrue(userRepository.findByUsername("Tim").isPresent()); if(checker.getKey()){
assertFalse(userRepository.findByUsername("Tom").isPresent()); userService.delete(checker.getValue());
user = userRepository.findByUsername("Tim").get(); }
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.getUsername(), "Tim");
assertEquals(user.getPassword(), "123456"); assertEquals(user.getPassword(),
"8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92");
// 检查账号状态
assertTrue(user.isEnabled()); assertTrue(user.isEnabled());
assertFalse(user.isDeleted()); 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 @Test
public void UserBaseTest_2(){ public void UserBaseTest_2(){
// 用户 User user = userService.findUserByUsername("Tim");
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);

View File

@ -8,83 +8,89 @@
</head> </head>
<body> <body>
<div class="logo-header" data-background-color="blue" style="width:100%">
<h1><font color="#FFFFFF">Error</font></h1> <div class="wrapper">
</div> <div class="main-header">
<nav class="navbar navbar-header navbar-expand-lg" data-background-color="blue2">
<div class="container-fluid"> <div class="container-fluid">
<div class="row-fluid"> <h1 style="color: white">Error Occurred</h1>
<div class="span12"> </div>
<h2> </nav>
检测到异常发生 </div>
</h2> <div class="main-panel">
<p> <div class="content">
<strong><strong>当服务器端程序内部某个模块抛出异常时,该界面就会被显示。此次异常的简要信息已被异常管理子系统收集并概括如下表:</strong></strong> <div class="page-inner">
</p> <div class="page-header">
<table class="table table-bordered"> <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> <thead>
<tr> <tr>
<th> <th scope="col">#</th>
编号 <th scope="col">信息项</th>
</th> <th scope="col"></th>
<th>
信息项
</th>
<th>
</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td> <td>0 </td>
0 <td>HTTP状态</td>
</td> <td class="text-primary" th:text="${http_status}"></td>
<td>
服务器返回HTTP状态
</td>
<td th:text="${http_status}">
</td>
</tr> </tr>
<tr> <tr>
<td> <td>1</td>
1 <td>异常类型</td>
</td> <td class="text-primary" th:text="${exception_name}"></td>
<td>
抛出的异常类型
</td>
<td th:text="${exception_name}">
</td>
</tr> </tr>
<tr> <tr>
<td> <td>2</td>
2 <td>附带消息</td>
</td> <td class="text-primary" th:text="${exception_message}"></td>
<td>
异常附带消息
</td>
<td th:text="${exception_message}">
</td>
</tr> </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> </tbody>
</table> </table>
<h3> </div>
运行栈相关信息补充
</h3> </div>
<p th:each="line : ${error_stack}"> <div class="card">
<span th:text="${line}"></span> <div class="card-header">
</p> <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>
</div> </div>
</div>
</body> </body>
</html> </html>

View File

@ -8,10 +8,23 @@
</head> </head>
<body> <body>
<div class="logo-header" data-background-color="blue" style="width:100%"> <div class="wrapper">
<h1><font color="#FFFFFF">404 Not Found</font></h1> <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>
</div>
</body> </body>