Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
XmlWebApplicationContext – загружает определение контекста из XML-файла, содержащегося внутри веб-приложения.public class User {
public void sendMessage(String message, String target) {
Sender sender = new Sender();
sender.send(message, target);
}
}
public class Sender {
public void send(String message, String target) {
System.out.println("Tweet: " + message + " to " + target);
}
}public interface Sender {
void sendMessage(String message, String target);
}public class TwitterSender implements Sender {
public void sendMessage(String message, String target) {
System.out.println("Tweet: " + message + " is sending to " + target);
}
}public class User {
private Sender sender;
public User(Sender sender) {
this.sender = sender;
}
public void setSender(Sender sender) {
this.sender = sender;
}
public void send(String message, String target) throws NullPointerException {
if (sender != null) {
sender.sendMessage(message, target);
} else {
throw new NullPointerException("Sender object is null");
}
}
}<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>@Configuration
public class AppConfig {...}@Configuration
public class AppConfig {
@Bean
public TwitterSender twitterSender() {
return new TwitterSender();
}
}@Configuration
public class AppConfig {
@Bean
public User user() {
return new User(twitterSender());
}
@Bean
public TwitterSender twitterSender() {
return new TwitterSender();
}
}public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext(AppConfig.class);
User user = context.getBean(User.class);
user.send("Hello!", "Nick");
}
}июл 01, 2018 2:37:09 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@4534b60d: startup date [Sun Jul 01 14:37:09 EEST 2018]; root of context hierarchy
Tweet: Hello! is sending to Nick@Component
public class TwitterSender implements Sender {...}
@Component
public class User {...}@Component
public class User {
private Sender sender;
@Autowired
public void setSender(Sender sender) {
this.sender = sender;
}
}@Configuration
@ComponentScan("app")
public class AppConfig {}июл 01, 2018 4:13:21 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2d8e6db6: startup date [Sun Jul 01 16:13:21 EEST 2018]; root of context hierarchy
Tweet: Hello! is sending to Nick@Component
public class EmailSender implements Sender {
public void sendMessage(String message, String target) {
System.out.println("Email: " + message + " to: " + target);
}
} at app.Main.main(Main.java:28)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'app.model.Sender' available: expected single matching bean but found 2: emailSender,twitterSendersender.type = emailpublic class Main {
public static final Properties config = new Properties();
static {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try (InputStream resourceStream = loader.getResourceAsStream("app.properties")) {
config.load(resourceStream);
} catch (IOException e) {
e.printStackTrace();
}
}
}public class TwitterSenderCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return Main.config.getProperty("sender.type").matches("twitter");
}
}
public class EmailSenderCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return Main.config.getProperty("sender.type").matches("email");
}
}@Component
@Conditional(value = TwitterSenderCondition.class)
public class TwitterSender implements Sender {...}
@Component
@Conditional(value = EmailSenderCondition.class)
public class EmailSender implements Sender {...}июл 01, 2018 4:57:53 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2d8e6db6: startup date [Sun Jul 01 16:57:53 EEST 2018]; root of context hierarchy
Email: Hello! to: Nickиюл 01, 2018 4:58:56 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2d8e6db6: startup date [Sun Jul 01 16:58:56 EEST 2018]; root of context hierarchy
Tweet: Hello! is sending to Nick<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
...
</dependencies>spring:
security:
user:
name: nick
password: 1234@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
}
}@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("foo")
.password("bar")
.roles("USER");
}
}@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("foo")
.password("bar")
.roles("USER")
.and()
.withUser("nick")
.roles("MODERATOR");
}
}@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("foo")
.password("$2y$12$kElDOfhm4WgdsDc4UQjgtuz0VEi5MOqVVhXaMoD1F2lhLivokhCqe")
.roles("USER")
.and()
.withUser("nick")
.roles("MODERATOR");
}
@Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("foo")
.password("{bcrypt}$2y$12$.JzV1A3qlof1.NzZpGaTYO1b26JGHevg0900QvwrSOdU3U9.g4hta")
.roles("USER");
}
// @Bean
// public PasswordEncoder getPasswordEncoder() {
// return new BCryptPasswordEncoder();
// }
}@Controller
public class IndexController {
@GetMapping("/")
public String index() {
return "index";
}
@GetMapping("/user/index")
public String user_index() {
return "/user/index";
}
@GetMapping("/admin/index")
public String admin_index() {
return "/admin/index";
}
}@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("foo")
.password("$2y$12$kElDOfhm4WgdsDc4UQjgtuz0VEi5MOqVVhXaMoD1F2lhLivokhCqe")
.roles("USER")
.and()
.withUser("admin")
.password("$2y$12$DQlTV6V1wMKEoCIW5lo1huAn2/bRk4hULDmRS5Jw6YW7HayHV4K66")
.roles("ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "static/css", "static/js").permitAll()
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/admin/**").hasRole("ADMIN")
.and().formLogin();
}
@Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
UserRepository repository;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
return new MyUserDetails(s);
}
}public class MyUserDetails implements UserDetails {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
}
private String userName;
public MyUserDetails(String userName) {
this.userName = userName;
}
public MyUserDetails() {
}
@Override
public String getPassword() {
return "$2y$12$8fKhxW71f4DzkzXYCh592.I.cd1uKkMrNwrHAApR1x5KHJ3qy1IjS";
}
@Override
public String getUsername() {
return userName;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- PostgreSQL -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency> jpa:
database: POSTGRESQL
show-sql: true
hibernate:
ddl-auto: create-drop
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
datasource:
platform: postgres
url: jdbc:postgresql://localhost:5432/ejournal
username: ejournal_user
password: 123456
driverClassName: org.postgresql.Driver@Entity
@Table(name = "profile")
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column(name = "user_name")
private String userName;
private String password;
private boolean active;
private String roles;
}@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
UserRepository repository;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
Optional<User> user = repository.findByUserName(s);
user.orElseThrow(() -> new UsernameNotFoundException("User not found: " + s));
return user.map(MyUserDetails::new).get();
}
}public interface UserRepository extends JpaRepository<User, Integer> {
Optional<User> findByUserName(String userName);
}public class MyUserDetails implements UserDetails {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorityList;
}
private String userName;
private String password;
private boolean active;
private List<GrantedAuthority> authorityList;
public MyUserDetails(User userName) {
this.userName = userName.getUserName();
this.password = userName.getPassword();
this.active = userName.isActive();
this.authorityList = Arrays.stream(userName.getRoles().split(",")).map(SimpleGrantedAuthority::new).collect(Collectors.toList());
}
public MyUserDetails() {
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return userName;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return active;
}
}<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" xmlns:th="http://www.thymeleaf.org">
<title>Index page</title>
</head>
<body>
<h1>Hello, world!</h1>
</body>
</html><!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<title>Hello, world!</title>
</head>
<body class="bg-light">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="#">Электронный деканат</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExample05"
aria-controls="navbarsExample05" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExample05">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="#">Главная</a>
</li>
<li class="nav-item active">
<a class="nav-link" href="#">Студенты <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Группы</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Кафедры</a>
</li>
</ul>
<form class="form-inline mt-2 mt-md-0">
<input class="form-control mr-sm-2" type="text" placeholder="Введите текст" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Поиск</button>
</form>
</div>
</nav>
<div class="container">
<div class="py-5 text-center">
<h2>Управление студентами</h2>
<p class="lead">На данной странице вы можете добавить, отредактировать поля или удалить студентов кафедры</p>
</div>
<div class="row">
<div class="col">
<h2>Группа АИ-171</h2>
</div>
<div class="col col-lg-3">
<a th:href="@{~/add_student}" class="btn btn-lg btn-block btn-outline-primary" role="button"
aria-disabled="true">Добавить студента</a>
</div>
</div>
<br/>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th class="text-justify">#</th>
<th class="text-justify">Фамилия</th>
<th class="text-justify">Имя</th>
<th class="text-justify">Отчество</th>
<th class="text-justify">Почта</th>
<th class="text-justify">Телефон</th>
<th class="text-justify">Адрес</th>
</tr>
</thead>
<tbody>
<tr th:each="student : ${students}">
<td class="align-middle"><span th:text="${student.id}"/></td>
<td class="align-middle"><span th:text="${student.lastName}"/></td>
<td class="align-middle"><span th:text="${student.firstName}"/></td>
<td class="align-middle"><span th:text="${student.patronymic}"/></td>
<td class="align-middle"><span th:text="${student.email}"/></td>
<td class="align-middle"><span th:text="${student.phone}"/></td>
<td class="align-middle"><span th:text="${student.address}"/></td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
</body>
</html><!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<title>Добавление студента</title>
</head>
<body class="bg-light">
<div class="container">
<div class="py-5 text-center">
<h2>Добавление студента</h2>
<p class="lead">Заполните поля и нажмите кнопку 'Добавить студента'</p>
</div>
<form method="post" class="needs-validation" novalidate>
<div class="row">
<div class="col-md-12">
<h4 class="mb-3">Поля для заполнения</h4>
<div class="row">
<div class="col-md-4 mb-3">
<label for="lastName">Фамилия</label>
<input type="text" class="form-control" id="lastName" placeholder=""
value="" required>
</div>
<div class="col-md-4 mb-3">
<label for="firstName">Имя</label>
<input type="text" class="form-control" id="firstName" placeholder=""
value="" required>
</div>
<div class="col-md-4 mb-3">
<label for="patronymic">Отчество</label>
<input type="text" class="form-control" id="patronymic" placeholder=""
value="" required>
</div>
</div>
<div class="mb-3">
<label for="email">Электронная почта</label>
<input type="email" class="form-control" id="email"
placeholder="" value="" required>
</div>
<div class="mb-3">
<label for="phone">Телефон</label>
<input type="text" class="form-control" id="phone"
placeholder="(ХХХ) ХХХ-ХХХХ" value="" required>
</div>
<div class="mb-3">
<label for="address">Домашний адрес</label>
<input type="text" class="form-control" id="address" placeholder="" value=""
required>
</div>
<hr class="mb-4">
<button class="btn btn-primary btn-lg btn-block" type="submit" value="Submit">Добавить студента</button>
</form>
</div>
</div>
</div>
<br/><br/><br/>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
</body>
</html>@Controller
public class StudentController {
@GetMapping("/")
public String index(Model model) {
return "index";
}
@GetMapping("/add_student")
public String addStudent(Model model) {
return "add_student";
}
} <div class="col col-lg-3">
<a th:href="@{~/add_student}" class="btn btn-lg btn-block btn-outline-primary" role="button"
aria-disabled="true">Добавить студента</a>
</div>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>@Service
public class JwiUtil {
private String PRIVATE_KEY = "670d4918c206e1bfec75bcaf637dc5b8";
private String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 8))
.signWith(SignatureAlgorithm.HS512, PRIVATE_KEY).compact();
}
}@Service
public class JwiUtil {
private String PRIVATE_KEY = "670d4918c206e1bfec75bcaf637dc5b8";
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 8))
.signWith(SignatureAlgorithm.HS512, PRIVATE_KEY).compact();
}
public boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
private boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
private String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
private Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
private <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(PRIVATE_KEY).parseClaimsJws(token).getBody();
}
}@Data
public class AuthRequest {
private String username;
private String password;
}@Data
public class AuthResponse {
private final String jwt;
}@org.springframework.web.bind.annotation.RestController
public class RestController {
@Autowired
private AuthenticationManager authManager;
@Autowired
private JwtUtil jwiUtil;
@Autowired
MyUserDetailsService userDetailsService;
@PostMapping(value = "/auth")
public ResponseEntity<?> createAuthToken(@RequestBody AuthRequest request) throws BadCredentialsException {
try {
authManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
);
} catch (BadCredentialsException ex) {
ex.printStackTrace();
}
final UserDetails userDetails = userDetailsService.loadUserByUsername(request.getUsername());
final String jwt = jwiUtil.generateToken(userDetails);
return ResponseEntity.ok(new AuthResponse(jwt));
}
}@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
MyUserDetailsService userDetailsService;
@Autowired
JwtRequestFilter filter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
// Авторизация
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/", "static/css", "static/js").permitAll()
.antMatchers("/auth").permitAll()
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/admin/**").hasRole("ADMIN")
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}@GetMapping(value = "/helloworld")
public String helloWorldRequest(Principal principal) {
final UserDetails userDetails = userDetailsService.loadUserByUsername(principal.getName());
return "<h1>Hello " + userDetails.getAuthorities().toString() + " </h1>";
}@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/", "static/css", "static/js").permitAll()
.antMatchers("/auth").permitAll()
.antMatchers("/helloworld").authenticated()
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/admin/**").hasRole("ADMIN")
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}@Component
public class JwtRequestFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Autowired
MyUserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
final String authHeader = httpServletRequest.getHeader("Authorization");
String jwt = null;
String username = null;
if (authHeader != null && authHeader.startsWith("Bearer ")) {
jwt = authHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwt, userDetails)) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(token);
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// Авторизация
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/", "static/css", "static/js").permitAll()
.antMatchers("/auth").permitAll()
.antMatchers("/helloworld","/me").authenticated()
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/admin/**").hasRole("ADMIN")
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);
}
}

spring:
jpa:
database: POSTGRESQL
show-sql: true
hibernate:
ddl-auto: create-drop
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
datasource:
platform: postgres
url: jdbc:postgresql://ec2-176-34-183-20.eu-west-1.compute.amazonaws.com:5432/d60ukqmkatvcpg
username: xvlmxbawwxafdu
password: a1439fbcffbfdd6ad208df91670a37c73d8ed12d18cd6de91c1485c5841774b9
driverClassName: org.postgresql.DriverMicrosoft Windows [Version 10.0.18362.476]
(c) Корпорация Майкрософт (Microsoft Corporation), 2019. Все права защищены.
C:\Users\nickg>git config --global user.name "Mykola Hodovychenko"
C:\Users\nickg>git config --global user.email hodovychenko@opu.ua
C:\Users\nickg>git config --list
http.sslcainfo=C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
http.sslbackend=openssl
diff.astextplain.textconv=astextplain
core.autocrlf=true
core.fscache=true
core.symlinks=false
core.editor="C:\\Program Files\\Notepad++\\notepad++.exe" -multiInst -notabbar -nosession -noPlugin
credential.helper=manager
user.name=Mykola Hodovychenko
user.email=hodovychenko@opu.ua
gui.recentrepo=E:/spring/testproject3
C:\Users\nickg>C:\Users\nickg>heroku login
heroku: Press any key to open up the browser to login or q to exit:
Opening browser to https://cli-auth.heroku.com/auth/browser/630e1a02-f90e-4217-8170-cd71d7fc700e
Logging in... done
Logged in as hodovychenko@opu.uaC:\Users\nickg>cd d:\springdemo\ejo
d:\springdemo\ejo>git init
Initialized empty Git repository in d:/springdemo/ejo/.git/d:\springdemo\ejo>heroku git:remote -a opnu-ej
set git remote heroku to https://git.heroku.com/opnu-ej.gitd:\springdemo\ejo>git add .
warning: LF will be replaced by CRLF in .gitignore.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in .mvn/wrapper/MavenWrapperDownloader.java.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in .mvn/wrapper/maven-wrapper.properties.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in mvnw.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in mvnw.cmd.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in pom.xml.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in src/main/java/com/example/ejo/EjoApplication.java.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in src/test/java/com/example/ejo/EjoApplicationTests.java.
The file will have its original line endings in your working directory
d:\springdemo\ejo>git commit -am "initial commit"
[master (root-commit) 162bc53] initial commit
16 files changed, 886 insertions(+)
create mode 100644 .gitignore
create mode 100644 .mvn/wrapper/MavenWrapperDownloader.java
create mode 100644 .mvn/wrapper/maven-wrapper.jar
create mode 100644 .mvn/wrapper/maven-wrapper.properties
create mode 100644 mvnw
create mode 100644 mvnw.cmd
create mode 100644 pom.xml
create mode 100644 src/main/java/com/example/ejo/Controller.java
create mode 100644 src/main/java/com/example/ejo/EjoApplication.java
create mode 100644 src/main/java/com/example/ejo/Group.java
create mode 100644 src/main/java/com/example/ejo/GroupRepository.java
create mode 100644 src/main/java/com/example/ejo/Service.java
create mode 100644 src/main/java/com/example/ejo/Student.java
create mode 100644 src/main/java/com/example/ejo/StudentRepository.java
create mode 100644 src/main/resources/application.yml
create mode 100644 src/test/java/com/example/ejo/EjoApplicationTests.javad:\springdemo\ejo>git push heroku master
Enumerating objects: 32, done.
Counting objects: 100% (32/32), done.
Delta compression using up to 6 threads
Compressing objects: 100% (23/23), done.
Writing objects: 100% (32/32), 54.39 KiB | 9.06 MiB/s, done.
Total 32 (delta 1), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Java app detected
remote: -----> Installing JDK 1.8... done
remote: -----> Executing: ./mvnw -DskipTests clean dependency:list install
remote: [INFO] Scanning for projects...
...
remote: [INFO] Replacing main artifact with repackaged archive
remote: [INFO]
remote: [INFO] --- maven-install-plugin:2.5.2:install (default-install) @ ejo ---
remote: [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/shared/maven-shared-utils/0.4/maven-shared-utils-0.4.pom
remote: [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/shared/maven-shared-utils/0.4/maven-shared-utils-0.4.pom (4.0 kB at 450 kB/s)
remote: [INFO] Downloading from central: https://repo.maven.apache.org/maven2/classworlds/classworlds/1.1-alpha-2/classworlds-1.1-alpha-2.jar
remote: [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/shared/maven-shared-utils/0.4/maven-shared-utils-0.4.jar
remote: [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/classworlds/classworlds/1.1-alpha-2/classworlds-1.1-alpha-2.jar (38 kB at 1.1 MB/s)
remote: [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0.15/plexus-utils-3.0.15.jar
remote: [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/shared/maven-shared-utils/0.4/maven-shared-utils-0.4.jar (155 kB at 2.0 MB/s)
remote: [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0.15/plexus-utils-3.0.15.jar (239 kB at 3.0 MB/s)
remote: [INFO] Installing /tmp/build_bee447e74484e663663b1d166f8e9456/target/ejo-0.0.1-SNAPSHOT.jar to /app/tmp/cache/.m2/repository/com/example/ejo/0.0.1-SNAPSHOT/ejo-0.0.1-SNAPSHOT.jar
remote: [INFO] Installing /tmp/build_bee447e74484e663663b1d166f8e9456/pom.xml to /app/tmp/cache/.m2/repository/com/example/ejo/0.0.1-SNAPSHOT/ejo-0.0.1-SNAPSHOT.pom
remote: [INFO] ------------------------------------------------------------------------
remote: [INFO] BUILD SUCCESS
remote: [INFO] ------------------------------------------------------------------------
remote: [INFO] Total time: 20.474 s
remote: [INFO] Finished at: 2019-11-26T21:46:52Z
remote: [INFO] ------------------------------------------------------------------------
remote: -----> Discovering process types
remote: Procfile declares types -> (none)
remote: Default types for buildpack -> web
remote:
remote: -----> Compressing...
remote: Done: 84.1M
remote: -----> Launching...
remote: Released v5
remote: https://opnu-ej.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/opnu-ej.git
* [new branch] master -> master
d:\springdemo\ejo>










Content-Dispositiontext/plain@RestController
public class HelloController {}@RestController
public class HelloController {
public String hello() {
return "hello";
}
}@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
}@GetMapping("/room/{id}")
public void getRoomById() {
}@GetMapping("/room/{id}")
public void getRoomById(@PathVariable(value = "id") int roomId) {
// ...
}@GetMapping("/room/{id1}/{id2}")
public void getRoomById(@PathVariable(value = "id1") int blockId, @PathVariable(value = "id2") int roomId) {
// ...
}// запрос: http://localhost:8080/room?room_id=250&block_id=10
@GetMapping("/room")
public void getRoomById(@RequestParam(value = "room_id") int roomId, @RequestParam(value = "block_id") int blockId) {
// ...
}@PostMapping("/book")
public void bookRoom(@RequestParam(value = "room_id") int room_id,
@RequestParam(value = "firstname") String firstname,
@RequestParam(value = "lastname") String lastname,
@RequestParam(value = "days") int days) {
// ...
} @GetMapping("/roominfo")
public Room getRoomInfoById(@RequestParam(value = "room_id") int roomId) {
return new Room(roomId, "Отличная комната!", 2, 200);
}public class Room {
private Integer id;
private String roomInfo;
private Integer roomCapacity;
private double price;
public Room(Integer id, String roomInfo, Integer roomCapacity, double price) {
this.id = id;
this.roomInfo = roomInfo;
this.roomCapacity = roomCapacity;
this.price = price;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRoomInfo() {
return roomInfo;
}
public void setRoomInfo(String roomInfo) {
this.roomInfo = roomInfo;
}
public Integer getRoomCapacity() {
return roomCapacity;
}
public void setRoomCapacity(Integer roomCapacity) {
this.roomCapacity = roomCapacity;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}public class Student {
private String firstname;
private String lastname;
private String phone;
private int age;
public Student(String firstname, String lastname, String phone, int age) {
this.firstname = firstname;
this.lastname = lastname;
this.phone = phone;
this.age = age;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"firstname='" + firstname + '\'' +
", lastname='" + lastname + '\'' +
", phone='" + phone + '\'' +
", age=" + age +
'}';
}
}@PostMapping("/student")
public void addStudent(@RequestBody Student student) {
System.out.println(student);
}@GetMapping("/student")
public ResponseEntity<?> getStudentById(@RequestParam(value = "id") int studentId) {
if (studentId < 1) {
return ResponseEntity.badRequest().body("Invalid id");
} else {
return ResponseEntity.ok(new Student("Ivan", "Ivanov", "223322", 20));
}
}

<dependencies>
...
<!-- jpa, crud repository -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- PostgreSQL -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
</dependencies>spring:
jpa:
database: POSTGRESQL
show-sql: true
hibernate:
ddl-auto: create-drop
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
datasource:
platform: postgres
url: jdbc:postgresql://localhost:5432/ejournal
username: ejournal_user
password: 123456
driverClassName: org.postgresql.Driver@Entity
@Table(name = "students")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
private int age;
}<dependencies>
...
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>@Entity
@Table(name = "students")
@Data
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
private int age;
}@org.springframework.stereotype.Service
public class Service {
public void addStudent(Student student, int id) {
// Добавление нового студента
}
public List<Student> getAllStudents() {
// Получение списка студентов
}
}@RestController
public class Controller {
@Autowired
private Service service;
@PostMapping("/student")
public void addStudent(@RequestBody Student student) {
service.addStudent(student);
}
@GetMapping("/student")
public List<Student> getAllStudents() {
return service.getAllStudents();
}
}@Entity
@Table(name = "groups")
@Data
public class Group {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
@OneToMany(mappedBy = "group")
private List<Student> studentList;
}public interface StudentRepository extends JpaRepository<Student, Integer> {
}@org.springframework.stereotype.Service
public class Service {
@Autowired
private StudentRepository studentRepo;
public void addStudent(Student student) {
studentRepo.save(student);
}
public List<Student> getAllStudents() {
return studentRepo.findAll();
}
}@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String firstname;
private String lastname;
private int age;
@ManyToOne (fetch = FetchType.LAZY,optional = false)
@JoinColumn(name = "group_id",nullable = false)
@JsonIgnore
private Group group;
}@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "groups")
public class Group {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@OneToMany(mappedBy = "group", cascade = CascadeType.ALL)
private List<Student> students;
public void addStudent(Student student) {
students.add(student);
}
}@RestController
public class Controller {
@Autowired
private Service service;
@PostMapping("/student/{group_id}")
public void addStudent(@RequestBody Student student, @PathVariable(name = "group_id") int group_id) {
service.addStudent(student, group_id);
}
@GetMapping("/student")
public List<Student> getAllStudents() {
return service.getAllStudents();
}
@PostMapping("/group")
public void addGroup(@RequestBody Group group) {
service.addGroup(group);
}
@GetMapping("/group")
public List<Group> getAllGroups() {
return service.getAllGroups();
}
}public interface GroupRepository extends JpaRepository<Group, Integer> {}@org.springframework.stereotype.Service
public class Service {
@Autowired
private StudentRepository studentRepo;
@Autowired
private GroupRepository groupRepo;
public void addStudent(Student student, int id) {
Group g = groupRepo.getOne(id);
student.setGroup(g);
studentRepo.save(student);
}
public List<Student> getAllStudents() {
return studentRepo.findAll();
}
public void addGroup(Group group) {
groupRepo.saveAndFlush(group);
}
public List<Group> getAllGroups() {
return groupRepo.findAll();
}
}
HttpServletResponseHttpServletRequestHttpServletResponse






























<form enctype="multipart/form-data" action="#" th:action="@{/}" th:object="${student}" method="post" class="needs-validation">
<div class="row">
<div class="col-md-12">
<h4 class="mb-3">Поля для заполнения</h4>
<div class="row">
<div class="col-md-6 mb-3">
<label for="lastName">Фамилия</label>
<input th:field="*{lastName}" type="text" class="form-control" id="lastName">
</div>
<div class="col-md-6 mb-3">
<label for="firstName">Имя</label>
<input th:field="*{firstName}" type="text" class="form-control" id="firstName">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="email">Электронная почта</label>
<input th:field="*{email}" type="text" class="form-control" id="email">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="age">Возраст</label>
<input th:field="*{age}" type="number" class="form-control" id="age">
</div>
</div>
<hr class="mb-4">
<button class="btn btn-primary btn-lg btn-block" type="submit" value="Submit">Добавить студента</button>
</div>
</div>
</form><?xml version="1.0" encoding="UTF-8"?>
<project ...>
...
<dependencies>
...
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
</dependencies>
...
</project>public class Student {
// Имя должно быть длиной от 2 до 50 символов
@Size(min = 2, max= 50, message = "First name should be from 2 to 50 characters")
private String firstName;
// Фамилия должна быть длиной от 2 до 50 символов
@Size(min = 2, max= 50, message = "Last name should be from 2 to 50 characters")
private String lastName;
// Возраст должен быть целым числом от 13 до 65
@Range(min = 13, max = 65, message = "Student age should be from 13 to 65 years")
private int age;
// Для валидации электронной почты используем регулярное выражение
@Pattern(regexp = "^[\\\\w!#$%&’*+/=?`{|}~^-]+(?:\\\\.[\\\\w!#$%&’*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\\\.)+[a-zA-Z]{2,6}$",
message = "Invalid email format")
private String email;
...
} @GetMapping("/")
public String addStudent(Model model) {
model.addAttribute("student", new Student());
return "index";
}
@PostMapping("/")
public String processAddStudentForm(@Valid Student student, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
System.out.println("Validation has been failed!");
return "index";
}
System.out.println(student);
list.add(student);
return "redirect:/";
}<div class="col-md-6 mb-3">
<label for="lastName">Фамилия</label>
<input th:field="*{lastName}" type="text" class="form-control" id="lastName">
<small class="text-danger" th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}"/>
</div><!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<title>Добавление студента</title>
</head>
<body class="bg-light">
<div class="container">
<div class="py-5 text-center">
<h2>Добавление студента</h2>
<p class="lead">Заполните поля и нажмите кнопку 'Добавить студента'</p>
</div>
<form enctype="multipart/form-data" action="#" th:action="@{/}" th:object="${student}" method="post">
<div class="row">
<div class="col-md-12">
<h4 class="mb-3">Поля для заполнения</h4>
<div class="row">
<div class="col-md-6 mb-3">
<label for="lastName">Фамилия</label>
<input th:field="*{lastName}" type="text" class="form-control" id="lastName">
<small class="text-danger" th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}"/>
</div>
<div class="col-md-6 mb-3">
<label for="firstName">Имя</label>
<input th:field="*{firstName}" type="text" class="form-control" id="firstName">
<small class="text-danger" th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}"/>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="email">Электронная почта</label>
<input th:field="*{email}" type="text" class="form-control" id="email">
<small class="text-danger" th:if="${#fields.hasErrors('email')}" th:errors="*{email}"/>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="age">Возраст</label>
<input th:value="${student.age > 0} ? ${student.age} : ''" th:field="*{age}" type="number" class="form-control" id="age">
<small class="text-danger" th:if="${#fields.hasErrors('age')}" th:errors="*{age}"/>
</div>
</div>
<hr class="mb-4">
<button class="btn btn-primary btn-lg btn-block" type="submit" value="Submit">Добавить студента</button>
</div>
</div>
</form>
</div>
</div>
</div>
<br/><br/><br/>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
</body>
</html>public class Student {
// Имя должно быть длиной от 2 до 50 символов
@Size(min = 2, max= 50, message = "First name should be from 2 to 50 characters")
private String firstName;
// Фамилия должна быть длиной от 2 до 50 символов
@Size(min = 2, max= 50, message = "Last name should be from 2 to 50 characters")
private String lastName;
// Возраст должен быть целым числом от 13 до 65
@Range(min = 13, max = 65, message = "Student age should be from 13 to 65 years")
private int age;
// Для валидации электронной почты используем регулярное выражение
@Pattern(regexp = "^[a-zA-Z0-9_!#$%&’*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$",
message = "Invalid email format")
private String email;
public Student(String firstName, String lastName, int age, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.email = email;
}
public Student() {
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}@Controller
public class StudentController {
private List<Student> list = new ArrayList<>();
@GetMapping("/")
public String addStudent(Model model) {
model.addAttribute("student", new Student());
return "index";
}
@PostMapping("/")
public String processAddStudentForm(@Valid Student student, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "index";
}
System.out.println(student);
list.add(student);
return "redirect:/";
}
}<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<title>Добавление студента</title>
</head>
<body class="bg-light">
<div class="container">
<div class="py-5 text-center">
<h2>Добавление студента</h2>
<p class="lead">Заполните поля и нажмите кнопку 'Добавить студента'</p>
</div>
<form enctype="multipart/form-data" action="#" th:action="@{/}" th:object="${student}" method="post">
<div class="row">
<div class="col-md-12">
<h4 class="mb-3">Поля для заполнения</h4>
<div class="row">
<div class="col-md-6 mb-3">
<label for="lastName">Фамилия</label>
<input th:field="*{lastName}" type="text" class="form-control" id="lastName">
<small class="text-danger" th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}"/>
</div>
<div class="col-md-6 mb-3">
<label for="firstName">Имя</label>
<input th:field="*{firstName}" type="text" class="form-control" id="firstName">
<small class="text-danger" th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}"/>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="email">Электронная почта</label>
<input th:field="*{email}" type="text" class="form-control" id="email">
<small class="text-danger" th:if="${#fields.hasErrors('email')}" th:errors="*{email}"/>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="age">Возраст</label>
<input th:value="${student.age > 0} ? ${student.age} : ''" th:field="*{age}" type="number" class="form-control" id="age">
<small class="text-danger" th:if="${#fields.hasErrors('age')}" th:errors="*{age}"/>
</div>
</div>
<div class="form-group">
<label for="file">Choose file:</label>
<input type="file" name="file" class="form-control-file" id="file">
</div>
<hr class="mb-4">
<button class="btn btn-primary btn-lg btn-block" type="submit" value="Submit">Добавить студента</button>
</div>
</div>
</form>
</div>
</div>
</div>
<br/><br/><br/>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
</body>
</html>




