Similar presentations:
Аспектно-ориентированное программирование
1.
SpringAOP
Transactions
Servlet API
Spring MVC
2.
AOPАспектно-ориентированное программирование - это методика,
дополняющая ООП-парадигму, позволяющая реализовывать
сквозную функционалтьность (например, выполнять внутри
транзакции все методы, которые помечены аннотацией
@Transactional)
3.
Основные терминыАспект (aspect) - модуль или класс, реализующий сквозную функциональность.
Аспект изменяет поведение остального кода, применяя совет в точках
соединения, определённых некоторым срезом.
Точка соединения (join point) - точка в выполняемой программе, где следует
применить совет.
Например, метод с аннотацией @Transactional. В Spring AOP точка соединения это всегда вызов метода.
Совет (advice) - действие (метод аспекта), выполняемое аспектом в конкретной
точке соединения. Совет может быть выполнен до, после или вместо точки
соединения.
Срез (pointcut) - набор точек соединения. Срез определяет, подходит ли данная
точка соединения к данному совету. Для определения среза в спринге по
умолчанию используется язык выражений AspectJ.
4.
Чтобы использовать Spring AOP, в конфигурации надо добавить аннотацию@EnableAspectJAutoProxy
@Configuration
@EnableAspectJAutoProxy
public class ApplicationConfig {
...
}
Аналог в XML-конфигурации
<aop:aspectj-autoproxy/>
5.
Чтобы объявить класс аспектом, надо поставить над ним аннотацию @Aspect.@Aspect
@Service <- аннотация @Aspect не добавляет бин в контекст
public class AspectExample {
Logger log = LoggerFactory.getLogger(AspectExample.class);
@Around("execution(* ru.bellintegrator.practice.controller.impl.PersonControllerImpl.persons())")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("INVOCATION METHOD:" + joinPoint.getSignature().toShortString());
//method invocation
Object returnValue = joinPoint.proceed();
log.info("METHOD:" + joinPoint.getSignature().toShortString() + "RETURNS:" + returnValue);
return returnValue;
}
}
6.
Пример можно посмотреть в гитхабе:https://github.com/azEsm/empty_project/tree/aspect_example
Более подробно про аспекты в спринге:
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
7.
TransactionsСпринг предоставляет возможность декларативно управлять транзакциями. Это
снижает вероятность ошибок и делает код более читаемым за счёт того, что
бизнес логика отделяется от системной.
В спринге для создания транзакции достаточно поставить над методом
аннотацию @Transactional.
@Transactional
public void businessLogic() {
// работа с БД через EntityManager
}
8.
Параметры аннотации @TransactionaltransactionManager
propagation
isolation
timeout
readOnly
rollbackFor
noRollbackFor
9.
Transaction Propagation BehaviorsREQUIRED - если транзакция есть, выполнение продолжается в рамках текущей транзакции.
Если нет, стартует новая.
SUPPORTS - если транзакция есть, выполнение продолжается в рамках текущей транзакции.
Если нет, выполняется без транзакции.
MANDATORY - если транзакция есть, выполнение продолжается в рамках текущей транзакции.
Если нет, бросается исключение.
REQUIRES_NEW - всегда создаётся новая транзакция. Если выполняется в рамках транзакции,
создаётся вложенная транзакция. Текущая транзакция приостанавливается.
NOT_SUPPORTED - всегда выполняется без транзакции. Если выполняется в рамках
транзакции, текущая транзакция приостанавливается.
NEVER - всегда выполняется без транзакции. Если выполняется в рамках транзакции, бросается
исключение.
NESTED - создаётся вложенная транзакция. Работает не во всех менеджерах транзакций.
10.
/*** Support a current transaction, execute non-transactionally if none exists.
* Analogous to EJB transaction attribute of the same name.
* <p>Note: For transaction managers with transaction synchronization,
* PROPAGATION_SUPPORTS is slightly different from no transaction at all,
* as it defines a transaction scope that synchronization will apply for.
* As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)
* will be shared for the entire specified scope. Note that this depends on
* the actual synchronization configuration of the transaction manager.
...
*/
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
11.
Аннотация @Transactionalразными контекстами:
● persistence context
● транзакции в базе данных
управляет
двумя
12.
Аннотация @Transactional определяет транзакцию в базе данных. Но работает врамках persistence context’а. Persistence context в JPA - это EntityManager. В
hibernate он реализован через Session.
Persistence context - это объект, который отслеживает состояние определённых
java объектов (hibernate entities) и отвечает за то, чтобы изменения в этих
объектах когда-нибудь были сброшены в базу данных.
Один EntityManager может быть использован в нескольких транзакциях в базе
данных
@PersistenceContext(type=PersistenceContextType.EXTENDED)
private EntityManager em;
13.
Но обычно в рамках одной транзакции используется один EntityManager.@PersistenceContext
private EntityManager em;
package javax.persistence;
/**
* Specifies whether a transaction-scoped or extended
* persistence context is to be used in {@link PersistenceContext}.
* If not specified, a transaction-scoped persistence context is used.
*
* @since Java Persistence 1.0
*/
public enum PersistenceContextType {
/**
* Transaction-scoped persistence context
*/
TRANSACTION,
/**
* Extended persistence context
*/
EXTENDED
}
14.
Может возникнуть вопрос, почему EntityManager в объекте устанавливается одинраз, но при этом в при каждом вызове транзакционного метода используется
новый EntityManager. Дело в том, что за интерфейсом EntityManager стоит
прокси-объект.
Обычно
используется
объект
SharedEntityManagerInvocationHandler,
который
реализует
интерфейс
EntityManager. Это можно увидеть в дебагере.
15.
Для extended контекста EntityManager будет выглядеть так16.
Extended context можно безопасно использовать в JEE-контейнерах в Statefulбинах, т.к. там контейнер управляет многопоточным доступом. В спринге
использовать extended context не рекомендуется, т.к. бины, хранящие состояние
(например, singleton) никак не синхронизированы.
The @PersistenceContext annotation has an optional attribute type, which defaults to
PersistenceContextType.TRANSACTION. This default is what you need to receive a shared
EntityManager proxy. The alternative, PersistenceContextType.EXTENDED, is a completely different
affair: This results in a so-called extended EntityManager, which is not thread-safe and hence must
not be used in a concurrently accessed component such as a Spring-managed singleton bean.
Extended EntityManagers are only supposed to be used in stateful components that, for example,
reside in a session, with the lifecycle of the EntityManager not tied to a current transaction but rather
being completely up to the application.
https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#orm-jpadao
17.
Для работы аннотации @Transactional используются трикомпонента:
● EntityManager proxy
● Transactional aspect (Spring AOP)
● Transaction manager
18.
Transactional AspectTransactional Aspect - это аспект типа around. Этот аспект
реализован в классе TransactionInterceptor. Аспект выполняет
две основные задачи:
● перед вызовом метода определяет, надо ли стартовать
новую транзакцию или выполнять метод в рамках
существующей
(решение
делегируется
менеджеру
транзакций)
● после выполнения метода определяет, коммитить или
откатывать транзакцию.
19.
package org.springframework.transaction.interceptor;/**
* AOP Alliance MethodInterceptor for declarative transaction
* management using the common Spring transaction infrastructure
* ({@link org.springframework.transaction.PlatformTransactionManager}).
* ...
*/
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
….
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
https://github.com/spring-projects/spring-framework/blob/master/springtx/src/main/java/org/springframework/transaction/interceptor/TransactionInterceptor.java
20.
Transaction ManagerПеред вызовом транзакционного метода менеджер транзакций определяет:
● надо ли создавать новый EntityManager
● надо ли стартовать новую транзакцию в БД
Определяется это исходя из следующих условий:
● выполняется ли метод уже в рамках существующей транзакции
● какое значение атрибута propagation аннотации @Transactional (например,
для значения REQUIRES_NEW всегда создаётся новая транзакция)
Если необходимо создать новую транзакцию, менеджер транзакций создаёт
новый EntityManager.
21.
22.
Конфигурация транзакций@Configuration
@EnableTransactionManagement
public class ApplicationConfig {
Аннотация @EnableTransactionManagement в конфигурации показывает спрингу, что к
методам с аннотацией @Transactional надо применять аспект TransactionInterceptor.
Также необходимо добавить в контекст бин PlatformTransactionManager. Например
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
Более подробно про транзакции в спринге:
https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction
23.
Servlet APIServlet API - это спецификация для обработки запросов.
Реализовано только для http.
Основные пакеты:
javax.servlet - классы и интерфейсы, не зависящие от протокола
javax.servlet.http - классы и интерфейсы, специфичные для
протокола http
24.
Servlet API, как и JDBC - это спецификация. Содержит восновном интерфейсы. Контейнер сервлетов - это конкретная
реализация спецификации.
Самые распространённые контейнеры сервлетов:
● Tomcat
● Jetty
● Undertow
25.
Основная задача сервлета - принимать запрос от клиента иформировать ответ.
Основной метод сервлета - это service.
void service(ServletRequest request, ServletResponse response)
26.
Пример HTTP-запросаGET /wiki/страница HTTP/1.1
Host: ru.wikipedia.org
User-Agent: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9b5) Gecko/2008050509
Firefox/3.0b5
Accept: text/html
Connection: close
(пустая строка)
(дальше идёт тело HTTP-запроса. Например, какие-то параметры, JSON и т.п.)
27.
Пример ответа на HTTP-запросHTTP/1.1 200 OK
Date: Wed, 11 Feb 2009 11:20:59 GMT
Server: Apache
X-Powered-By: PHP/5.2.4-2ubuntu5wm1
Last-Modified: Wed, 11 Feb 2009 11:20:59 GMT
Content-Language: ru
Content-Type: text/html; charset=utf-8
Content-Length: 1234
Connection: close
(пустая строка)
(страница в HTML-формате, JSON и т.п.)
28.
HttpServlet - класс предназначенный для обработки запросов и формированияответов по протоколу HTTP.
В этом классе есть отдельные методы для разных HTTP-методов
https://www.tutorialspoint.com/http/http_methods.htm
https://www.w3schools.com/tags/ref_httpmethods.asp
Например:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws
ServletException, IOException
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws
ServletException, IOException
29.
Классы HttpServletRequest и HttpServletResponse - этопредставления HTTP-запроса и HTTP-ответа в виде javaобъектов.
Чтобы
читать
данные
из
тела
HTTP-запроса
у
HttpServletRequest есть метод getReader(), который возвращает
BufferedReader, а у HttpServletResponse есть метод getWriter(), с
помощью которого можно писать данные в тело HTTP-ответа.
30.
Дескриптор развёртыванияДескриптор развёртывания - это конфигурационный файл, в
котором описано, как разворачивать приложение в контейнере
сервлетов. В этом файле описывается, какие URL будут
передаваться определённому сервлету, какие URL требуют
аутентификации и т.п. Этот файл должен называться web.xml и
находиться в директории WEB-INF. По этому дескриптору
создаётся ServletContext.
31.
Пример дескриптора:<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="3.0" ...>
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>ru.bellintegrator.example.servlets.Example</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>example</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
32.
Передача параметров в Servlet<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="3.0" ...>
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>ru.bellintegrator.example.servlets.Example</servlet-class>
<init-param>
<param-name>someParameter</param-name>
<param-value>42</param-value>
</init-param>
</servlet>
...
</web-app>
public class Example extends HttpServlet {
protected String someParameter;
@Override <- метод из класса GenericServlet
public void init(ServletConfig servletConfig) throws ServletException {
someParameter = servletConfig.getInitParameter("someParameter");
}
...
33.
Аналогичная конфигурация аннотациями(доступно с версии Servlet API 3.0):
@WebServlet(
urlPatterns = "/*",
initParams = {
@WebInitParam(
name = "someParameter",
value = "42"
)
}
)
public class Example extends HttpServlet {
...
34.
Задание параметров контекста (доступные для всех сервлетов)<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="3.0" ...>
<context-param>
<param-name>contextParam</param-name>
<param-value>value</param-value>
</context-param>
...
</web-app>
public class Example extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
String contextParam = request
.getSession()
.getServletContext()
.getInitParameter("contextParam");
...
}
35.
Конфигурация приложения<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="3.0" ...>
...
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>public/greeting.html</welcome-file>
</welcome-file-list>
...
</web-app>
36.
По умолчанию экземпляр сервлета создаётся в неопределённый момент временимежду запуском приложения и запросом к сервлету. Если надо создать экземпляр
сервлета при старте приложения, надо добавить параметр load-on-startup:
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>ru.bellintegrator.example.servlets.Example</servlet-class>
<load-on-startup>5</load-on-startup>
</servlet>
Параметр тэга load-on-startup - это порядок. Например, если в приложении есть два
сервлета и у одного этот параметр - 3, а у другого - 5, то первым будет создан сервлет
с параметром 3.
37.
Динамическое добавление сервлетов@WebListener
public class ExampleContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext context = servletContextEvent.getServletContext();
ServletRegistration.Dynamic servlet = context.addServlet (
"dynamicServlet",
DynamicServlet.class.getName()
);
servlet.setInitParameter("someParameter", "42");
servlet.addMapping(“/dynamic”);
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
...
}
}
38.
Добавление листенера в web.xml (аналог аннотации@WebListener)
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="3.0" ...>
…
<listener>
<listener-class>
ru.bellintegrator.example.init.ExampleContextListener
</listener-class>
</listener>
...
</web-app>
39.
ФильтрыФильтры используются для предварительной обработки запроса перед тем, как
он попадёт в сервлет, а также для обработки ответа после сервлета. Запрос
можно проходить через несколько фильтров (шаблон проектирования chain of
responsibilities)
Фильтры конфигурируются аналогично сервлетам в web.xml
<filter>
<filter-name>requestLoggingFilter</filter-name>
<filter-class>ru.bellintegrator.example.servlets.filters.RequestLoggingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestLoggingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
40.
Класс RequestLoggingFilter должен реализовать интерфейс javax.servlet.Filterpublic interface Filter {
void init(FilterConfig config) throws ServletException;
void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain
) throws IOException, ServletException;
void destroy();
}
Необходимо переопределить метод doFilter и в конце обработки вызвать у параметра
chain метод doFilter. После этого обработка продолжится в следующем фильтре или в
сервлете.
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain
) throws IOException, ServletException {
log.debug(“Filter”);
chain.doFilter(request, response);
}
41.
Жизненный цикл сервлетаЗагрузка класса сервлета — когда контейнер получает запрос для сервлета,
то происходит загрузка класса сервлета в память и вызов конструктора без
параметров.
Инициализация класса сервлета — после того как класс загружен контейнер
инициализирует объект ServletConfig для этого сервлета и внедряет его
через init() метод. Это и есть место где сервлет класс преобразуется из
обычного класса в сервлет.
Обработка запросов — после инициализации сервлет готов к обработке
запросов. Для каждого запроса клиента контейнер сервлетов порождает
новый поток и вызывает метод service() путем передачи ссылки на объект
ответа и запроса.
Удаление из Service — когда контейнер останавливается или
останавливается приложение, то контейнер сервлетов уничтожает классы
сервлетов путем вызова destroy() метода.
42.
Spring MVCSpring MVC работает поверх Servlet API и существенно
упрощает работу с ним. Реализует архитектуру Model-ViewController.
Model (модель) - данные приложения
View (отображение, представление) - отображение данных для
пользователя. Например, HTML-страница или JSON
Controller - отвечает за обработку запросов пользователя и
создание отображения на основе данных приложения.
43.
За обработку HTTP-запросов в Spring MVC отвечаетDispatcherServlet.
44.
XML-конфигурация Spring MVC<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="3.0" ...>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/dispatcher-config.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
45.
Начиная с версии Servlet 3.0 можно конфигурировать ServletContext без web.xml. В спринге дляэтого есть интерфейс WebApplicationInitializer.
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
XmlWebApplicationContext appContext = new XmlWebApplicationContext();
appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(
"dispatcher",
new DispatcherServlet(appContext)
);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
46.
package org.springframework.web;…
/**
* Interface to be implemented in Servlet 3.0+ environments in order to configure the
* {@link ServletContext} programmatically -- as opposed to (or possibly in conjunction
* with) the traditional {@code web.xml}-based approach.
…
* @author Chris Beams
* @since 3.1
* @see SpringServletContainerInitializer
…
*/
public interface WebApplicationInitializer {
void onStartup(ServletContext servletContext) throws ServletException;
47.
package org.springframework.web;...
import javax.servlet.ServletContainerInitializer;
…
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
/**
* Delegate the {@code ServletContext} to any {@link WebApplicationInitializer}
* implementations present on the application classpath.
…
*/
@Override
public void onStartup(
@Nullable Set<Class<?>> webAppInitializerClasses,
ServletContext servletContext
) throws ServletException {
...
48.
Конфигурация Spring MVC без XMLpublic class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(AppConfig.class);
// Manage the lifecycle of the root application context
servletContext.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(DispatcherConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(
"dispatcher",
new DispatcherServlet(dispatcherContext)
);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
49.
dispatcher-config.xml<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven />
</beans>
50.
DispatcherConfig.class@Configuration
@EnableWebMvc
public class DispatcherConfig {
...
}
51.
Все
HTTP-запросы
в
Spring
MVC
направляются
в
DispatcherServlet.doService(...).
Далее после некоторой обработки запроса вызывается метод интерфейса
HandlerMapping
HandlerExecutionChain getHandler(HttpServletRequest request)
Этот метод определяет, какие фильтры и контроллер будет обрабатывать
запрос. Создаёт цепочку обработки запроса.
● Контроллер обрабатывает запрос, выполняет какую-то бизнес-логику и
возвращает имя отображения.
● Чтобы получить нужное отображение, DispatcherServlet в цикле обращается
ко всем зарегистрированным реализациям ViewResolver и вызывает метод
View resolveViewName(String viewName, Locale locale) throws Exception;
Возвращается первое полученное не null значение. View - это объект, который
рендерит HTML-страницу по данным из модели.
● DispatcherServlet передаёт в полученный объект View данные модели в
виде атрибутов и генерирует HTTP-ответ.
52.
/*** Indicates that an annotated class is a "Controller" (e.g. a web controller).
*
* <p>This annotation serves as a specialization of {@link Component @Component},
* allowing for implementation classes to be autodetected through classpath scanning.
* It is typically used in combination with annotated handler methods based on the
* {@link org.springframework.web.bind.annotation.RequestMapping} annotation.
*
* ...
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
...
53.
@Controller@RequestMapping("/hello")
public class HelloController {
@RequestMapping(method = RequestMethod.GET)
public String printHello(ModelMap model) {
model.addAttribute("message", "Hello!");
return "hello";
}
}
<html>
<head>
<title>Hello Spring MVC</title>
</head>
<body>
<h2>${message}</h2>
</body>
</html>
54.
/*** A convenience annotation that is itself annotated with
* {@link Controller @Controller} and {@link ResponseBody @ResponseBody}.
* <p>
* Types that carry this annotation are treated as controllers where
* {@link RequestMapping @RequestMapping} methods assume
* {@link ResponseBody @ResponseBody} semantics by default.
*
* ...
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
55.
/*** Annotation that indicates a method return value should be bound to the web
* response body. Supported for annotated handler methods in Servlet environments.
*
* <p>As of version 4.0 this annotation can also be added on the type level in
* which case it is inherited and does not need to be added on the method level.
*
* ...
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
56.
@RestController@RequestMapping(value = "/house", produces = APPLICATION_JSON_VALUE)
public class DummyControllerImpl implements DummyController {
…
@RequestMapping(value = "/person", method = {POST})
public ResponseView person(@RequestBody PersonView person) {
return dummyService.add(person);
}
…
}
public class ResponseView {
boolean success;
}
{"success":"true"}
57.
Path variables@RequestMapping(value = "/library/book/{isbn}", method = GET)
public String bookByIsbn(
@PathVariable("isbn") String bookIdentifier
){
...
}
url: http://localhost:8080/library/book/42
@RequestMapping(value = "/library/book/{id:[\\d]+}", method = GET)
public String bookById(
@PathVariable("id") long bookId
){
...
}
url: http://localhost:8080/library/book/42
NOT: http://localhost:8080/library/book/aaa
58.
Request parameters@RequestMapping(value = "/library/book", method = GET)
@ResponseBody
public String bookByIsbn(
@RequestParam("isbn") String bookIdentifier
){
...
}
url: http://localhost:8080/library/book?isbn=42
Статья про RequestMapping: https://www.baeldung.com/spring-requestmapping
59.
@RestControllerAdvicepublic class ExceptionHandlerController {
@ExceptionHandler(Exception.class)
public String unhandledException(Exception e) {
return e.getMessage();
}
}
60.
@RestControllerAdvicepublic class ResponseBodyHandler implements ResponseBodyAdvice<Object> {
private final Logger log = LoggerFactory.getLogger(getClass());
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends
HttpMessageConverter<?>> aClass) { return true; }
@Override
public Object beforeBodyWrite(Object body, MethodParameter methodParameter,
MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass,
ServerHttpRequest serverHttpRequest, ServerHttpResponse response) {
ResultView resultView = new ResultView();
…Логика определяющая что именно нужно подкладывать в результат работы метода или вообще заменять его
resultView.data = body;
return resultView; }
}