08.
Spring Boot and MVC<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
...
</project>
<dependency>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>base-project</artifactId>
<version>0.1.0</version>
<packaging>pom</packaging>
<modules>
<module>book-service</module>
</modules>
</project>
public class CourseLister {
// ...
public List<Course> сoursesByAuthor(String name) {
List<Course> allCourses = finder.findAll();
return allCourses
.stream()
.filter(course -> course.getAuthor().equals(name))
.collect(Collectors.toList());
}
}
public interface CourseFinder {
List<Course> findAll();
}
public class CourseLister {
private CourseFinder finder;
public CourseLister() {
this.finder = new FileBasedCourseFinder("courses.txt");
}
//...
}
@Component
public class CourseLister {
private final CourseFinder finder;
@Autowired
public CourseLister(CourseFinder finder) {
this.finder = finder;
}
public List<Course> сoursesByAuthor(String name) {
List<Course> allCourses = finder.findAll();
return allCourses
.stream()
.filter(course -> course.getAuthor().equals(name))
.collect(Collectors.toList());
}
}
public class Main {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
public class Main {
public static void main(String[] args) {
Class<?> petClass = Pet.class;
Constructor<?> constructor = pet.getConstructors()[0];
// экземпляр класса Pet
Object pet = constructor.newInstance("Барбос", 4);
}
}
public class Pet {
public Pet(String name, int age) {
/* инициализация в конструкторе... */
}
}
@Component
public class Wife {
private final Husband husband;
public Wife(Husband husband) {
this.husband = husband;
}
}
@Component
public class Husband {
private final Wife wife;
public Husband(Wife wife) {
this.wife = wife;
}
}
public class Main {
public static void main(String[] args) {
new Wife(
new Husband(
/* что подставлять сюда? */
)
);
}
}
@Component
public class Wife {
private Husband husband;
@Autowired
public void setHusband(Husband husband) {
this.husband = husband;
}
}
@Component
public class Husband {
private Wife wife;
@Autowired
public void setWife(Wife wife) {
this.wife = wife;
}
}
@Component
public class Wife {
@Autowired
private Husband husband;
}
@Component
public class Husband {
@Autowired
private Wife wife;
}
@Configuration
public class Config {
@Bean
public Husband husband() {
return new Husband();
}
@Bean
public Wife wife() {
return new Wife();
}
}
@Component
public class UserServiceImpl implements UserService {
...
}
@Component
public class AuditUserService implements UserService {
@Autowired
private UserService origin;
...
}
@Component
public class EmailUserService implements UserService {
@Autowired
private UserService origin;
...
}
@Component("userServiceImpl")
public class UserServiceImpl implements UserService {
...
}
@Component("auditUserService")
public class AuditUserService implements UserService {
@Autowired
@Qualifier("userServiceImpl")
private UserService origin;
...
}
@Component("emailUserService")
public class EmailUserService implements UserService {
@Autowired
@Qualifier("auditUserService")
private UserService origin;
...
}
@Component
@Primary
public class EmailUserService implements UserService {
...
}
@Service
public class SecurityService {
public Response authorize(Request request) {
if (request.getHeader(AUTHORIZATION).startsWith("Basic")) {
return tryBasicAuth(request);
}
if (request.getHeader(AUTHORIZATION).startsWith("Bearer")) {
return tryJwt(request);
}
return new Response(UNAUTHORIZED);
}
}
public abstract class SecurityService {
protected SecurityService next;
public void setNext(SecurityService next) {
this.next = next;
}
public abstract Response authorize(Request request);
}
@Service
public class BasicAuthSecurityService extends SecurityService {
@Override
public Response authorize(Request request) {
if (request.getHeader(AUTHORIZATION).startsWith("Basic")) {
return tryBasicAuth(request);
}
return next.authorize(request);
}
}
@Service
public class JwtAuthSecurityService extends SecurityService {
@Override
public Response authorize(Request request) {
if (request.getHeader(AUTHORIZATION).startsWith("Bearer")) {
return tryJwtAuth(request);
}
return next.authorize(request);
}
}
@Service
public class UnauthorizedSecurityService extends SecurityService {
@Override
public Response authorize(Request request) {
return new Response(UNAUTHORIZED);
}
}
@Service("basic")
public class BasicAuthSecurityService extends SecurityService {
...
}
@Service("jwt")
public class JwtAuthSecurityService extends SecurityService {
...
}
@Service("unauthorized")
public class UnauthorizedSecurityService extends SecurityService {
...
}
@Service
public class SecurityServiceFacade {
private final SecurityService entry;
public SecurityServiceFacade(Map<String, SecurityService> services) {
SecurityService basic = services.get("basic");
SecurityService jwt = services.get("jwt");
SecurityService unauthorized = services.get("unauthorized");
basic.setNext(jwt);
jwt.setNext(unauthorized);
this.entry = basic;
}
public Response authorize(Request request) {
return this.entry(request);
}
}
public abstract class SecurityService {
protected SecurityService next;
public void setNext(SecurityService next) {
this.next = next;
}
public abstract SecurityType getType();
public abstract Response authorize(Request request);
}
@Service
public class BasicAuthSecurityService extends SecurityService {
...
public SecurityType getType() {
return BASIC;
}
}
@Service
public class JwtAuthSecurityService extends SecurityService {
...
public SecurityType getType() {
return JWT;
}
}
@Service
public class UnauthorizedSecurityService extends SecurityService {
...
public SecurityType getType() {
return UNAUTHORIZED;
}
}
@Service
public class SecurityServiceFacade {
private final SecurityService entry;
public SecurityServiceFacade(List<SecurityService> servicesList) {
Map<SecurityType, SecurityService> services =
servicesList.stream()
.collect(toMap(SecurityService::getType, identity()));
SecurityService basic = services.get(BASIC);
SecurityService jwt = services.get(JWT);
SecurityService unauthorized = services.get(UNAUTHORIZED);
basic.setNext(jwt);
jwt.setNext(unauthorized);
this.entry = basic;
}
public Response authorize(Request request) {
return this.entry(request);
}
}
@Service
@Order(0)
public class BasicAuthSecurityService extends SecurityService {
...
public SecurityType getType() {
return BASIC;
}
}
@Service
@Order(1)
public class JwtAuthSecurityService extends SecurityService {
...
public SecurityType getType() {
return JWT;
}
}
@Service
@Order(2)
public class UnauthorizedSecurityService extends SecurityService {
...
public SecurityType getType() {
return UNAUTHORIZED;
}
}
@Service
public class SecurityServiceFacade {
private final SecurityService entry;
public SecurityServiceFacade(List<SecurityService> servicesList) {
if (servicesList.isEmpty()) {
throw new IllegalStateException("List cannot be empty");
}
for (int i = 1; i < servicesList; i++) {
SecurityService previous = servicesList.get(i - 1);
SecurityService current = servicesList.get(i);
previous.setNext(current);
}
this.entry = servicesList.get(0);
}
public Response authorize(Request request) {
return this.entry(request);
}
}
Logger logger = LoggerFactory.getLogger(LoggingDemoController.class);
logger.trace("Маршрут выполнения программы");
logger.debug("Отладочное сообщение");
logger.info("Информационное сообщение");
logger.warn("Предупреждение");
logger.error("Сообщение об ошибке");
logging.level.root=TRACE
java -jar myApp-0.0.1-SNAPSHOT.jar --trace
@RestController
@RequestMapping("/api")
public class CourseController {
private final CourseRepository courseRepository;
public CourseController(CourseRepository courseRepository) {
this.courseRepository = courseRepository;
}
@GetMapping("/courses")
public List<Course> courseTable() {
return courseRepository.findAll();
}
}
[
{
"id": 1,
"author": "Петров А.В.",
"title": "Основы кройки и шитья"
},
{
"id": 2,
"author": "Мошкина А.В",
"title": "Введение в архитектурный дизайн"
}
]
@Component
public class Listener {
private final ObjectMapper objectMapper;
public Listener(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@EventListener(ApplicationStartedEvent.class)
public void onApplicationStart() throws Exception {
String json = objectMapper.writeValueAsString(new Course(1L, "Иван Иванов", "Курс по Java"));
Course parsedCourse = objectMapper.readValue(json, Course.class);
// parsedCourse будет таким же, как и изначальный Course
}
}
public class Course {
private Long id;
private String author;
private String title;
// getters, setters, constructor
}
public interface CourseRepository {
Optional<Course> findById(Long id);
List<Course> findAll();
Course save(Course course);
}
@Component
public class InMemoryCourseRepository implements CourseRepository {
private final List<Course> courses;
private final AtomicLong idGenerator = new AtomicLong(0);
public InMemoryCourseRepository() {
courses = new CopyOnWriteArrayList<>();
courses.add(new Course(idGenerator.incrementAndGet(), "Петров А.В.", "Основы кройки и шитья"));
courses.add(new Course(idGenerator.incrementAndGet(), "Мошкина А.В", "Введение в архитектурный дизайн"));
}
@Override
public Optional<Course> findById(Long id) {
return courses.stream()
.filter(c -> c.getId() == id)
.findFirst();
}
@Override
public List<Course> findAll() {
// чтобы случайное изменение в полученном списке не поменяло данные внутри InMemoryCourseRepository
return new ArrayList<>(courses);
}
@Override
public Course save(Course course) {
// если id == null, курс новый
if (course.getId() == null) {
course.setId(idGenerator.incrementAndGet());
courses.add(course);
// чтобы изменение в Course не повлияло на состояние в InMemoryCourseRepository
return new Course(course);
}
// иначе - это операция update
else {
synchronized(this) {
for (Course c : courses) {
if (c.getId() == course.getId()) {
c.setAuthor(course.getAuthor());
c.setName(course.getName());
return course;
}
}
// иначе курс не найден
throw new CourseNotFoundException("No course with id=" + course.getId());
}
}
}
}
@RestController
@RequestMapping("/api")
public class CourseController {
@GetMapping("/courses/{id}")
public Course getCourse(@PathVariable("id") Long id) {
return courseRepository.findById(id).orElseThrow();
}
}
public class CourseRequestToUpdate {
private String author;
private String title;
// геттеры, сеттеры...
}
@RestController
@RequestMapping("/api")
public class CourseController {
@PutMapping("/courses/{id}")
public void updateCourse(@PathVariable Long id,
@RequestBody CourseRequestToUpdate request) {
Course course = courseRepository.findById(id).orElseThrow();
course.setTitle(request.getTitle());
course.setAuthor(request.getAuthor());
courseRepository.save(course);
}
}
public class CourseRequestToCreate {
private String author;
private String title;
// геттеры, сеттеры...
}
@RestController
@RequestMapping("/api")
public class CourseController {
@PostMapping("/courses")
public Course createCourse(@RequestBody CourseRequestToCreate request) {
Course course = new Course(request.getTitle(), request.getName());
return courseRepository.save(course);
}
}
@RestController
@RequestMapping("/api")
public class CourseController {
@DeleteMapping("/courses/{id}")
public void deleteCourse(@PathVariable Long id) {
courseRepository.deleteById(id);
}
}
@ExceptionHandler
public ResponseEntity<ApiError> noSuchElementExceptionHandler(NoSuchElementException ex) {
return new ResponseEntity<>(
new ApiError(ex.getMessage()),
HttpStatus.NOT_FOUND
);
}
@RestControllerAdvice
public class HandleErrorService {
@ExceptionHandler
public ResponseEntity<ApiError> noSuchElementExceptionHandler(NoSuchElementException ex) {
return new ResponseEntity<>(
new ApiError(ex.getMessage()),
HttpStatus.NOT_FOUND
);
}
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
public class CourseRequestToUpdate {
@NotBlank(message = "Course author has to be filled")
private String author;
@NotBlank(message = "Course title has to be filled")
private String title;
// геттеры, сеттеры...
}
@PutMapping("/{id}")
public void updateCourse(@PathVariable Long id,
@Valid @RequestBody CourseRequestToUpdate request) {
Course course = courseRepository.findById(request.getId()).orElseThrow();
course.setTitle(request.getTitle());
course.setAuthor(request.getAuthor());
courseRepository.save(course);
}