I would advise you to start with the stack spring-boot, security, jpa, velocity (does not require bulky configuration classes / xml). According to the structure: 1) Maine controller - description of the main page via ModelMap (buttons - registration, authorization, chat dialog box)
@RequestMapping(value = "", method = {RequestMethod.GET, RequestMethod.HEAD}) public String MainPage(ModelMap model) { model.addAttribute("title_page", "Чат сервер"); final User user = securityService.findLoggedIn(); if (user != null) { model.addAttribute("authuser", user); } MainContent(model, domain); GeneratePageBlock(model, "/site/" + domain + "/pages/main.vm"); return "/site/" + domain + "/index"; }
2) Registration / authorization controllers, the implementation of the JpaRepository<User, Long> interface for processing user data, where User implementation of the UserDetails interface -
@Entity @Table(name = "user") public class User implements UserDetails { @Id @GeneratedValue(generator = "increment") @GenericGenerator(name = "increment", strategy = "increment") @Column(name = "id") private Long id; @Column(name = "enabled") private Boolean enabled; @NotEmpty(message = "Заполните поле") @Column(name = "username") private String username; @NotEmpty(message = "Заполните поле") @Email(message = "Неверный формат Email") @Column(name = "email") private String email; @NotEmpty(message = "Заполните поле") @Size(min = 4, message = "Пароль должен содержать минимум {min} символа") @Column(name = "password") private String password; @Transient private String passwordConfirm; @Column(name = "roles") private String roles; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public void setEnabled(Boolean enabled) { this.enabled = enabled; } @Override public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPasswordConfirm() { return passwordConfirm; } public void setPasswordConfirm(String passwordConfirm) { this.passwordConfirm = passwordConfirm; } public String getRoles() { return roles; } public void setRoles(String roles) { this.roles = roles; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return enabled; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { if (roles != null) { if (roles.contains("ADMIN")) { return AuthorityUtils.createAuthorityList("ROLE_ADMIN", "ROLE_MODERATOR", "ROLE_USER"); } else if (roles.contains("MODERATOR")) { return AuthorityUtils.createAuthorityList("ROLE_MODERATOR", "ROLE_USER"); } } return AuthorityUtils.createAuthorityList("ROLE_USER"); } }
Sample Registration Controller Logic -
@RequestMapping(value = "registration", method = RequestMethod.POST) public String registration(@ModelAttribute("user") User user, BindingResult result, ModelMap model, HttpServletRequest request) { model.addAttribute("title_page", "Регистрация - База знаний Lineage 2 Helios"); MainContent(model, domain); userValidator.validate(user, result); if (result.hasErrors()) { GeneratePageBlock(model, "/site/" + domain + "/pages/registration.vm"); return "/site/" + domain + "/index"; } final User user1 = new User(); user1.setUsername(user.getUsername()); user1.setEmail(user.getEmail()); user1.setPassword(new BCryptPasswordEncoder().encode(user.getPassword())); user1.setEnabled(false); user1.setRoles("ROLE_USER"); userService.save(user1); final User user_saved = userService.findByUsername(user1.getUsername()); eventPublisher.publishEvent(new OnRegistrationCompleteEvent(user_saved, getAppUrl(request))); model.addAttribute("message", "Регистрация прошла успешно, информация отправлена на Email: " + user.getEmail()); GeneratePageBlock(model, "/site/" + domain + "/pages/registrationSuccessful.vm"); return "/site/" + domain + "/index"; }
3) Chat itself - you can see a detailed example here -> https://github.com/salmar/spring-websocket-chat