Spring Boot技术栈博客企业前后端
(2-2 -用Gradle编译项目&)
2-2 -用Gradle编译项目&
gradle编译项目
(3-3 -编写程序代码及测试用例&)
3-3 -编写程序代码及测试用例&
Application.java
package com.waylau.spring.boot.blog;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
HelloController.java
package com.waylau.spring.boot.blog.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Hello World 控制器.
*/
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "Hello World! Welcome to visit waylau.com!";
}
}
ApplicationTests.java
package com.waylau.spring.boot.blog;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {
@Test
public void contextLoads() {
}
}
MainController.java
package com.waylau.spring.boot.blog.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import com.waylau.spring.boot.blog.domain.Authority;
import com.waylau.spring.boot.blog.domain.User;
import com.waylau.spring.boot.blog.service.AuthorityService;
import com.waylau.spring.boot.blog.service.UserService;
/**
* 主页控制器.
*/
@Controller
public class MainController {
private static final Long ROLE_USER_AUTHORITY_ID = 2L;
@Autowired
private UserService userService;
@Autowired
private AuthorityService authorityService;
@GetMapping("/")
public String root() {
return "redirect:/index";
}
@GetMapping("/index")
public String index() {
return "index";
}
/**
* 获取登录界面
* @return
*/
@GetMapping("/login")
public String login() {
return "login";
}
@GetMapping("/login-error")
public String loginError(Model model) {
model.addAttribute("loginError", true);
model.addAttribute("errorMsg", "登陆失败,账号或者密码错误!");
return "login";
}
@GetMapping("/register")
public String register() {
return "register";
}
/**
* 注册用户
* @param user
* @param result
* @param redirect
* @return
*/
@PostMapping("/register")
public String registerUser(User user) {
List<Authority> authorities = new ArrayList<>();
authorities.add(authorityService.getAuthorityById(ROLE_USER_AUTHORITY_ID));
user.setAuthorities(authorities);
userService.saveUser(user);
return "redirect:/login";
}
@GetMapping("/search")
public String search() {
return "search";
}
}
application.properties
server.port=8080
debug=true
# THYMELEAF
spring.thymeleaf.encoding=UTF-8
# 热部署静态文件
spring.thymeleaf.cache=false
# 使用HTML5标准
spring.thymeleaf.mode=HTML5
# DataSource
spring.datasource.url=jdbc:mysql://localhost/blog?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop
BlogController.java
package com.waylau.spring.boot.blog.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 主页控制器.
*
*/
@Controller
@RequestMapping("/blogs")
public class BlogController {
@GetMapping
public String listBlogs(@RequestParam(value="order",required=false,defaultValue="new") String order,
@RequestParam(value="tag",required=false) Long tag) {
System.out.print("order:" +order + ";tag:" +tag );
return "redirect:/index?order="+order+"&tag="+tag;
}
}
package com.waylau.spring.boot.blog.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.waylau.spring.boot.blog.vo.Menu;
/**
* 用户控制器.
*
*/
@Controller
@RequestMapping("/admins")
public class AdminController {
/**
* 获取后台管理主页面
* @return
*/
@GetMapping
public ModelAndView listUsers(Model model) {
List<Menu> list = new ArrayList<>();
list.add(new Menu("用户管理", "/users"));
list.add(new Menu("角色管理", "/roles"));
list.add(new Menu("博客管理", "/blogs"));
list.add(new Menu("评论管理", "/commits"));
model.addAttribute("list", list);
return new ModelAndView("/admins/index", "model", model);
}
}
UserspaceController.java
restful请求url,requestParam
package com.waylau.spring.boot.blog.controller;
import java.util.List;
import javax.validation.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.DeleteMapping;
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 org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import com.waylau.spring.boot.blog.domain.Blog;
import com.waylau.spring.boot.blog.domain.User;
import com.waylau.spring.boot.blog.service.BlogService;
import com.waylau.spring.boot.blog.service.UserService;
import com.waylau.spring.boot.blog.util.ConstraintViolationExceptionHandler;
import com.waylau.spring.boot.blog.vo.Response;
/**
* 用户主页空间控制器.
*
*/
@Controller
@RequestMapping("/u")
public class UserspaceController {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private UserService userService;
@Autowired
private BlogService blogService;
@GetMapping("/{username}")
public String userSpace(@PathVariable("username") String username, Model model) {
User user = (User)userDetailsService.loadUserByUsername(username);
model.addAttribute("user", user);
return "redirect:/u/" + username + "/blogs";
}
@GetMapping("/{username}/profile")
@PreAuthorize("authentication.name.equals(#username)")
public ModelAndView profile(@PathVariable("username") String username, Model model) {
User user = (User)userDetailsService.loadUserByUsername(username);
model.addAttribute("user", user);
return new ModelAndView("/userspace/profile", "userModel", model);
}
/**
* 保存个人设置
* @param user
* @param result
* @param redirect
* @return
*/
@PostMapping("/{username}/profile")
@PreAuthorize("authentication.name.equals(#username)")
public String saveProfile(@PathVariable("username") String username,User user) {
User originalUser = userService.getUserById(user.getId());
originalUser.setEmail(user.getEmail());
originalUser.setName(user.getName());
// 判断密码是否做了变更
String rawPassword = originalUser.getPassword();
PasswordEncoder encoder = new BCryptPasswordEncoder();
String encodePasswd = encoder.encode(user.getPassword());
boolean isMatch = encoder.matches(rawPassword, encodePasswd);
if (!isMatch) {
originalUser.setEncodePassword(user.getPassword());
}
userService.saveUser(originalUser);
return "redirect:/u/" + username + "/profile";
}
/**
* 获取编辑头像的界面
* @param username
* @param model
* @return
*/
@GetMapping("/{username}/avatar")
@PreAuthorize("authentication.name.equals(#username)")
public ModelAndView avatar(@PathVariable("username") String username, Model model) {
User user = (User)userDetailsService.loadUserByUsername(username);
model.addAttribute("user", user);
return new ModelAndView("/userspace/avatar", "userModel", model);
}
/**
* 保存头像
* @param username
* @param model
* @return
*/
@PostMapping("/{username}/avatar")
@PreAuthorize("authentication.name.equals(#username)")
public ResponseEntity<Response> saveAvatar(@PathVariable("username") String username, @RequestBody User user) {
String avatarUrl = user.getAvatar();
User originalUser = userService.getUserById(user.getId());
originalUser.setAvatar(avatarUrl);
userService.saveUser(originalUser);
return ResponseEntity.ok().body(new Response(true, "处理成功", avatarUrl));
}
@GetMapping("/{username}/blogs")
public String listBlogsByOrder(@PathVariable("username") String username,
@RequestParam(value="order",required=false,defaultValue="new") String order,
@RequestParam(value="category",required=false ) Long category,
@RequestParam(value="keyword",required=false,defaultValue="" ) String keyword,
@RequestParam(value="async",required=false) boolean async,
@RequestParam(value="pageIndex",required=false,defaultValue="0") int pageIndex,
@RequestParam(value="pageSize",required=false,defaultValue="10") int pageSize,
Model model) {
User user = (User)userDetailsService.loadUserByUsername(username);
model.addAttribute("user", user);
if (category != null) {
System.out.print("category:" +category );
System.out.print("selflink:" + "redirect:/u/"+ username +"/blogs?category="+category);
return "/u";
}
Page<Blog> page = null;
if (order.equals("hot")) { // 最热查询
Sort sort = new Sort(Direction.DESC,"reading","comments","likes");
Pageable pageable = new PageRequest(pageIndex, pageSize, sort);
page = blogService.listBlogsByTitleLikeAndSort(user, keyword, pageable);
}
if (order.equals("new")) { // 最新查询
Pageable pageable = new PageRequest(pageIndex, pageSize);
page = blogService.listBlogsByTitleLike(user, keyword, pageable);
}
List<Blog> list = page.getContent(); // 当前所在页面数据列表
model.addAttribute("order", order);
model.addAttribute("page", page);
model.addAttribute("blogList", list);
return (async==true?"/userspace/u :: #mainContainerRepleace":"/userspace/u");
}
/**
* 获取博客展示界面
* @param id
* @param model
* @return
*/
@GetMapping("/{username}/blogs/{id}")
public String getBlogById(@PathVariable("username") String username,@PathVariable("id") Long id, Model model) {
// 每次读取,简单的可以认为阅读量增加1次
blogService.readingIncrease(id);
boolean isBlogOwner = false;
// 判断操作用户是否是博客的所有者
if (SecurityContextHolder.getContext().getAuthentication() !=null && SecurityContextHolder.getContext().getAuthentication().isAuthenticated()
&& !SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString().equals("anonymousUser")) {
User principal = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal !=null && username.equals(principal.getUsername())) {
isBlogOwner = true;
}
}
model.addAttribute("isBlogOwner", isBlogOwner);
model.addAttribute("blogModel",blogService.getBlogById(id));
return "/userspace/blog";
}
/**
* 删除博客
* @param id
* @param model
* @return
*/
@DeleteMapping("/{username}/blogs/{id}")
@PreAuthorize("authentication.name.equals(#username)")
public ResponseEntity<Response> deleteBlog(@PathVariable("username") String username,@PathVariable("id") Long id) {
try {
blogService.removeBlog(id);
} catch (Exception e) {
return ResponseEntity.ok().body(new Response(false, e.getMessage()));
}
String redirectUrl = "/u/" + username + "/blogs";
return ResponseEntity.ok().body(new Response(true, "处理成功", redirectUrl));
}
/**
* 获取新增博客的界面
* @param model
* @return
*/
@GetMapping("/{username}/blogs/edit")
public ModelAndView createBlog(Model model) {
model.addAttribute("blog", new Blog(null, null, null));
return new ModelAndView("/userspace/blogedit", "blogModel", model);
}
/**
* 获取编辑博客的界面
* @param model
* @return
*/
@GetMapping("/{username}/blogs/edit/{id}")
public ModelAndView editBlog(@PathVariable("username") String username,@PathVariable("id") Long id, Model model) {
model.addAttribute("blog", blogService.getBlogById(id));
return new ModelAndView("/userspace/blogedit", "blogModel", model);
}
/**
* 保存博客
* @param username
* @param blog
* @return
*/
@PostMapping("/{username}/blogs/edit")
@PreAuthorize("authentication.name.equals(#username)")
public ResponseEntity<Response> saveBlog(@PathVariable("username") String username, @RequestBody Blog blog) {
User user = (User)userDetailsService.loadUserByUsername(username);
blog.setUser(user);
try {
blogService.saveBlog(blog);
} catch (ConstraintViolationException e) {
return ResponseEntity.ok().body(new Response(false, ConstraintViolationExceptionHandler.getMessage(e)));
} catch (Exception e) {
return ResponseEntity.ok().body(new Response(false, e.getMessage()));
}
String redirectUrl = "/u/" + username + "/blogs/" + blog.getId();
return ResponseEntity.ok().body(new Response(true, "处理成功", redirectUrl));
}
}
AdminController.java
package com.waylau.spring.boot.blog.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.waylau.spring.boot.blog.vo.Menu;
/**
* 用户控制器.
*
*/
@Controller
@RequestMapping("/admins")
public class AdminController {
/**
* 获取后台管理主页面
* @return
*/
@GetMapping
public ModelAndView listUsers(Model model) {
List<Menu> list = new ArrayList<>();
list.add(new Menu("用户管理", "/users"));
list.add(new Menu("角色管理", "/roles"));
list.add(new Menu("博客管理", "/blogs"));
list.add(new Menu("评论管理", "/commits"));
model.addAttribute("list", list);
return new ModelAndView("/admins/index", "model", model);
}
}
UserController.java
package com.waylau.spring.boot.blog.controller;
import java.util.ArrayList;
import java.util.List;
import javax.validation.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.DeleteMapping;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import com.waylau.spring.boot.blog.domain.Authority;
import com.waylau.spring.boot.blog.domain.User;
import com.waylau.spring.boot.blog.service.AuthorityService;
import com.waylau.spring.boot.blog.service.UserService;
import com.waylau.spring.boot.blog.util.ConstraintViolationExceptionHandler;
import com.waylau.spring.boot.blog.vo.Response;
/**
* 用户控制器.
*
*/
@RestController
@RequestMapping("/users")
@PreAuthorize("hasAuthority('ROLE_ADMIN')") // 指定角色权限才能操作方法
public class UserController {
@Autowired
private UserService userService;
@Autowired
private AuthorityService authorityService;
/**
* 查询所用用户
* @return
*/
@GetMapping
public ModelAndView list(@RequestParam(value="async",required=false) boolean async,
@RequestParam(value="pageIndex",required=false,defaultValue="0") int pageIndex,
@RequestParam(value="pageSize",required=false,defaultValue="10") int pageSize,
@RequestParam(value="name",required=false,defaultValue="") String name,
Model model) {
Pageable pageable = new PageRequest(pageIndex, pageSize);
Page<User> page = userService.listUsersByNameLike(name, pageable);
List<User> list = page.getContent(); // 当前所在页面数据列表
model.addAttribute("page", page);
model.addAttribute("userList", list);
return new ModelAndView(async==true?"users/list :: #mainContainerRepleace":"users/list", "userModel", model);
}
/**
* 获取 form 表单页面
* @param user
* @return
*/
@GetMapping("/add")
public ModelAndView createForm(Model model) {
model.addAttribute("user", new User(null, null, null, null));
return new ModelAndView("users/add", "userModel", model);
}
/**
* 新建用户
* @param user
* @param result
* @param redirect
* @return
*/
@PostMapping
public ResponseEntity<Response> create(User user, Long authorityId) {
List<Authority> authorities = new ArrayList<>();
authorities.add(authorityService.getAuthorityById(authorityId));
user.setAuthorities(authorities);
if(user.getId() == null) {
user.setEncodePassword(user.getPassword()); // 加密密码
}else {
// 判断密码是否做了变更
User originalUser = userService.getUserById(user.getId());
String rawPassword = originalUser.getPassword();
PasswordEncoder encoder = new BCryptPasswordEncoder();
String encodePasswd = encoder.encode(user.getPassword());
boolean isMatch = encoder.matches(rawPassword, encodePasswd);
if (!isMatch) {
user.setEncodePassword(user.getPassword());
}else {
user.setPassword(user.getPassword());
}
}
try {
userService.saveUser(user);
} catch (ConstraintViolationException e) {
return ResponseEntity.ok().body(new Response(false, ConstraintViolationExceptionHandler.getMessage(e)));
}
return ResponseEntity.ok().body(new Response(true, "处理成功", user));
}
/**
* 删除用户
* @param id
* @return
*/
@DeleteMapping(value = "/{id}")
public ResponseEntity<Response> delete(@PathVariable("id") Long id, Model model) {
try {
userService.removeUser(id);
} catch (Exception e) {
return ResponseEntity.ok().body( new Response(false, e.getMessage()));
}
return ResponseEntity.ok().body( new Response(true, "处理成功"));
}
/**
* 获取修改用户的界面,及数据
* @param user
* @return
*/
@GetMapping(value = "edit/{id}")
public ModelAndView modifyForm(@PathVariable("id") Long id, Model model) {
User user = userService.getUserById(id);
model.addAttribute("user", user);
return new ModelAndView("users/edit", "userModel", model);
}
}
MainController.java
package com.waylau.spring.boot.blog.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import com.waylau.spring.boot.blog.domain.Authority;
import com.waylau.spring.boot.blog.domain.User;
import com.waylau.spring.boot.blog.service.AuthorityService;
import com.waylau.spring.boot.blog.service.UserService;
/**
* 主页控制器.
*
*/
@Controller
public class MainController {
private static final Long ROLE_USER_AUTHORITY_ID = 2L;
@Autowired
private UserService userService;
@Autowired
private AuthorityService authorityService;
@GetMapping("/")
public String root() {
return "redirect:/index";
}
@GetMapping("/index")
public String index() {
return "index";
}
/**
* 获取登录界面
* @return
*/
@GetMapping("/login")
public String login() {
return "login";
}
@GetMapping("/login-error")
public String loginError(Model model) {
model.addAttribute("loginError", true);
model.addAttribute("errorMsg", "登陆失败,账号或者密码错误!");
return "login";
}
@GetMapping("/register")
public String register() {
return "register";
}
/**
* 注册用户
* @param user
* @param result
* @param redirect
* @return
*/
@PostMapping("/register")
public String registerUser(User user) {
List<Authority> authorities = new ArrayList<>();
authorities.add(authorityService.getAuthorityById(ROLE_USER_AUTHORITY_ID));
user.setAuthorities(authorities);
userService.saveUser(user);
return "redirect:/login";
}
@GetMapping("/search")
public String search() {
return "search";
}
}
(13-2 -后台实现&)
13-2 -后台实现&
User.java JPA校验
package com.waylau.spring.boot.blog.domain;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* User 实体
*
*/
@Entity // 实体
public class User implements UserDetails, Serializable {
private static final long serialVersionUID = 1L;
@Id // 主键
@GeneratedValue(strategy = GenerationType.IDENTITY) // 自增长策略
private Long id; // 用户的唯一标识
@NotEmpty(message = "姓名不能为空")
@Size(min=2, max=20)
@Column(nullable = false, length = 20) // 映射为字段,值不能为空
private String name;
@NotEmpty(message = "邮箱不能为空")
@Size(max=50)
@Email(message= "邮箱格式不对" )
@Column(nullable = false, length = 50, unique = true)
private String email;
@NotEmpty(message = "账号不能为空")
@Size(min=3, max=20)
@Column(nullable = false, length = 20, unique = true)
private String username; // 用户账号,用户登录时的唯一标识
@NotEmpty(message = "密码不能为空")
@Size(max=100)
@Column(length = 100)
private String password; // 登录时密码
@Column(length = 200)
private String avatar; // 头像图片地址
@ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.EAGER)
@JoinTable(name = "user_authority", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "authority_id", referencedColumnName = "id"))
private List<Authority> authorities;
protected User() { // JPA 的规范要求无参构造函数;设为 protected 防止直接使用
}
public User(String name, String email,String username,String password) {
this.name = name;
this.email = email;
this.username = username;
this.password = password;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Collection<? extends GrantedAuthority> getAuthorities() {
// 需将 List<Authority> 转成 List<SimpleGrantedAuthority>,否则前端拿不到角色列表名称
List<SimpleGrantedAuthority> simpleAuthorities = new ArrayList<>();
for(GrantedAuthority authority : this.authorities){
simpleAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority()));
}
return simpleAuthorities;
}
public void setAuthorities(List<Authority> authorities) {
this.authorities = authorities;
}
@Override
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void setEncodePassword(String password) {
PasswordEncoder encoder = new BCryptPasswordEncoder();
String encodePasswd = encoder.encode(password);
this.password = encodePasswd;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public String toString() {
return String.format("User[id=%d, username='%s', name='%s', email='%s', password='%s']", id, username, name, email,
password);
}
}
UserRepository.java
package com.waylau.spring.boot.blog.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import com.waylau.spring.boot.blog.domain.User;
/**
* 用户仓库.
*
*/
public interface UserRepository extends JpaRepository<User, Long>{
/**
* 根据用户名分页查询用户列表
* @param name
* @param pageable
* @return
*/
Page<User> findByNameLike(String name, Pageable pageable);
User findByUsername(String username);
}
UserService.java
package com.waylau.spring.boot.blog.service;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import com.waylau.spring.boot.blog.domain.User;
/**
* User 服务接口.
*/
public interface UserService {
/**
* 保存用户
* @param user
* @return
*/
User saveUser(User user);
/**
* 删除用户
* @param user
* @return
*/
void removeUser(Long id);
/**
* 删除列表里面的用户
* @param user
* @return
*/
void removeUsersInBatch(List<User> users);
/**
* 更新用户
* @param user
* @return
*/
User updateUser(User user);
/**
* 根据id获取用户
* @param user
* @return
*/
User getUserById(Long id);
/**
* 获取用户列表
* @param user
* @return
*/
List<User> listUsers();
/**
* 根据用户名进行分页模糊查询
* @param user
* @return
*/
Page<User> listUsersByNameLike(String name, Pageable pageable);
}
UserServiceImpl.java jpa模糊查询
package com.waylau.spring.boot.blog.service;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.waylau.spring.boot.blog.domain.User;
import com.waylau.spring.boot.blog.repository.UserRepository;
/**
* User 服务.
*
*/
@Service
public class UserServiceImpl implements UserService, UserDetailsService {
@Autowired
private UserRepository userRepository;
@Transactional
@Override
public User saveUser(User user) {
return userRepository.save(user);
}
@Transactional
@Override
public void removeUser(Long id) {
userRepository.delete(id);
}
@Transactional
@Override
public void removeUsersInBatch(List<User> users) {
userRepository.deleteInBatch(users);
}
@Transactional
@Override
public User updateUser(User user) {
return userRepository.save(user);
}
@Override
public User getUserById(Long id) {
return userRepository.getOne(id);
}
@Override
public List<User> listUsers() {
return userRepository.findAll();
}
@Override
public Page<User> listUsersByNameLike(String name, Pageable pageable) {
// 模糊查询
name = "%" + name + "%";
Page<User> users = userRepository.findByNameLike(name, pageable);
return users;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByUsername(username);
}
}
Response.java response响应数据体封装
package com.waylau.spring.boot.blog.vo;
/**
* 响应 值对象.
*
*/
public class Response {
private boolean success;
private String message;
private Object body;
/** 响应处理是否成功 */
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
/** 响应处理的消息 */
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
/** 响应处理的返回内容 */
public Object getBody() {
return body;
}
public void setBody(Object body) {
this.body = body;
}
public Response(boolean success, String message) {
this.success = success;
this.message = message;
}
public Response(boolean success, String message, Object body) {
this.success = success;
this.message = message;
this.body = body;
}
}
ConstraintViolationExceptionHandler.java 批量获取异常信息
/**
*
*/
package com.waylau.spring.boot.blog.util;
import java.util.ArrayList;
import java.util.List;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import org.apache.commons.lang3.StringUtils;
/**
* @author Administrator
*
*/
public class ConstraintViolationExceptionHandler {
/**
* 获取批量异常信息
* @param e
* @return
*/
public static String getMessage(ConstraintViolationException e) {
List<String> msgList = new ArrayList<>();
for (ConstraintViolation<?> constraintViolation : e.getConstraintViolations()) {
msgList.add(constraintViolation.getMessage());
}
String messages = StringUtils.join(msgList.toArray(), ";");
return messages;
}
}
(3-3 ,13-4-前台实现、测试&)
3-3 ,13-4-前台实现、测试&
register.html thymeleaf发送form表单提交
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{fragments/header :: header}">
</head>
<body>
<div class="container blog-content-container">
<form th:action="@{/register}" method="post">
<h2 class="form-signin-heading">注册成为博主</h2>
<div class="form-group col-md-5">
<label for="username" class="col-form-label">账号</label>
<input type="text" class="form-control" id="username" name="username" maxlength="50" placeholder="请输入账号,至少3个字符,至多20个">
</div>
<div class="form-group col-md-5">
<label for="email" class="col-form-label">邮箱</label>
<input type="email" class="form-control" id="email" name="email" maxlength="50" placeholder="请输入邮箱">
</div>
<div class="form-group col-md-5">
<label for="name" class="col-form-label">姓名</label>
<input type="text" class="form-control" id="name" name="name" maxlength="20" placeholder="请输入姓名,至少2个字符,至多20个" >
</div>
<div class="form-group col-md-5">
<label for="password" class="col-form-label">密码</label>
<input type="password" class="form-control" id="password" name="password" maxlength="30" placeholder="请输入密码,字母或特殊符号和数字结合" >
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">提交</button>
</div>
</form>
</div> <!-- /container -->
<div th:replace="~{fragments/footer :: footer}">...</div>
</body>
</html>
index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head th:replace="~{fragments/header :: header}">
</head>
<body>
<!-- Page Content -->
<div class="container blog-content-container">
<div class="row">
<!-- 左侧栏目 -->
<div class="col-md-4 col-xl-3">
<!-- 分类 -->
<div class="card ">
<h5 class="card-header"><i class="fa fa-bars" aria-hidden="true"></i> 菜单</h5>
<ul class="list-group blog-menu" th:each="menu : ${model.list}">
<a href="javascript:void(0)" class="list-group-item " th:title="${menu.name}" th:text="${menu.name}"
data-th-attr="url=${menu.url}">
用户管理
</a>
</div>
</div>
<!-- 右侧栏目 -->
<div class="col-md-8 col-xl-9">
<div class="card" id="rightContainer">
</div>
</div>
</div>
<!-- /.row -->
</div>
<!-- /.container -->
<div th:replace="~{fragments/footer :: footer}">...</div>
<!-- JavaScript -->
<script src="../../js/admins/main.js" th:src="@{/js/admins/main.js}"></script>
</body>
</html>
list.html
<div class="card-header bg-dark font-white">
<div class="input-group col-md-7 col-xl-6">
<input type="text" class="form-control" id="searchName"
placeholder="输入用户名称进行搜索"> <span class="input-group-btn">
<button class="btn btn-secondary" type="button" id="searchNameBtn">
<i class="fa fa-search" aria-hidden="true"></i>
</button>
</span> <a class="btn btn-primary" data-toggle="modal"
data-target="#flipFlop" role="button" id="addUser"><i
class="fa fa-plus" aria-hidden="true"></i></a>
</div>
</div>
<div id="mainContainer" class="container">
<div id="mainContainerRepleace" class="row">
<table class="table table-striped">
<thead>
<tr>
<th data-field="id">ID</th>
<th data-field="username">账号</th>
<th data-field="name">姓名</th>
<th data-field="email">邮箱</th>
<th data-field="authorities">角色</th>
<th data-field="operation">操作</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${userModel.userList}">
<td th:text="${user.id}">1</td>
<td th:text="${user.username}">1</td>
<td th:text="${user.name}">waylau</td>
<td th:text="${user.email}">waylau</td>
<td th:text="${user.authorities}">waylau</td>
<td>
<div>
<a class="blog-edit-user" data-toggle="modal"
data-target="#flipFlop" role="button"
data-th-attr="userId=${user.id}"> <i
class="fa fa-pencil-square-o" aria-hidden="true"></i>
</a> <a class="blog-delete-user" role="button"
data-th-attr="userId=${user.id}"> <i class="fa fa-times"
aria-hidden="true"></i>
</a>
</div>
</td>
</tr>
</tbody>
</table>
<div th:replace="~{fragments/page :: page}">...</div>
</div>
</div>
<!-- The modal -->
<div class="modal fade" id="flipFlop" tabindex="-1" role="dialog"
aria-labelledby="modalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="modalLabel">新增/编辑</h4>
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body" id="userFormContainer"></div>
<div class="modal-footer">
<button class="btn btn-primary" data-dismiss="modal" id="submitEdit">提交</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- JavaScript -->
<script src="../../js/users/main.js" th:src="@{/js/users/main.js}"></script>
main.js 前台发送restfule请求
/*!
* Bolg main JS.
*
* @since: 1.0.0 2017/3/9
* @author Way Lau <https://waylau.com>
*/
"use strict";
//# sourceURL=main.js
// DOM 加载完再执行
$(function() {
var _pageSize; // 存储用于搜索
// 根据用户名、页面索引、页面大小获取用户列表
function getUersByName(pageIndex, pageSize) {
$.ajax({
url: "/users",
contentType : 'application/json',
data:{
"async":true,
"pageIndex":pageIndex,
"pageSize":pageSize,
"name":$("#searchName").val()
},
success: function(data){
$("#mainContainer").html(data);
},
error : function() {
toastr.error("error!");
}
});
}
// 分页
$.tbpage("#mainContainer", function (pageIndex, pageSize) {
getUersByName(pageIndex, pageSize);
_pageSize = pageSize;
});
// 搜索
$("#searchNameBtn").click(function() {
getUersByName(0, _pageSize);
});
// 获取添加用户的界面
$("#addUser").click(function() {
$.ajax({
url: "/users/add",
success: function(data){
$("#userFormContainer").html(data);
},
error : function(data) {
toastr.error("error!");
}
});
});
// 获取编辑用户的界面
$("#rightContainer").on("click",".blog-edit-user", function () {
$.ajax({
url: "/users/edit/" + $(this).attr("userId"),
success: function(data){
$("#userFormContainer").html(data);
},
error : function() {
toastr.error("error!");
}
});
});
// 提交变更后,清空表单
$("#submitEdit").click(function() {
$.ajax({
url: "/users",
type: 'POST',
data:$('#userForm').serialize(),
success: function(data){
$('#userForm')[0].reset();
if (data.success) {
// 从新刷新主界面
getUersByName(0, _pageSize);
} else {
toastr.error(data.message);
}
},
error : function() {
toastr.error("error!");
}
});
});
// 删除用户
$("#rightContainer").on("click",".blog-delete-user", function () {
// 获取 CSRF Token
var csrfToken = $("meta[name='_csrf']").attr("content");
var csrfHeader = $("meta[name='_csrf_header']").attr("content");
$.ajax({
url: "/users/" + $(this).attr("userId") ,
type: 'DELETE',
beforeSend: function(request) {
request.setRequestHeader(csrfHeader, csrfToken); // 添加 CSRF Token
},
success: function(data){
if (data.success) {
// 从新刷新主界面
getUersByName(0, _pageSize);
} else {
toastr.error(data.message);
}
},
error : function() {
toastr.error("error!");
}
});
});
});
add.html
<div class="container">
<form th:action="@{/users}" method="post" th:object="${userModel.user}" id="userForm">
<input type="hidden" name="id" th:value="*{id}">
<div class="form-group ">
<label for="username" class="col-form-label">账号</label>
<input type="text" class="form-control" id="username" name="username" th:value="*{username}" maxlength="50" placeholder="请输入账号,至少3个字符,至多20个">
</div>
<div class="form-group">
<label for="email" class="col-form-label">邮箱</label>
<input type="email" class="form-control" id="email" name="email" th:value="*{email}" maxlength="50" placeholder="请输入邮箱">
</div>
<div class="form-group">
<label for="name" class="col-form-label">姓名</label>
<input type="text" class="form-control" id="name" name="name" th:value="*{name}" maxlength="20" placeholder="请输入姓名,至少2个字符,至多20个" >
</div>
<div class="form-group">
<label for="password" class="col-form-label">密码</label>
<input type="password" class="form-control" id="password" name="password" th:value="*{password}" maxlength="30" placeholder="请输入密码,字母或特殊符号和数字结合" >
</div>
<div class="form-group">
<label for="authorities" class="col-form-label">角色</label>
<select id="authorities" name="authorityId" class="form-control form-control-chosen" data-placeholder="请选择">
<option value="1">管理员</option>
<option value="2">博主</option>
</select>
</div>
</form>
</div>
<!-- /.container -->