Идентификатор клиента: 2 02 февраля 2022 г., 09:59:11.271 СЕРЬЕЗНЫЙ [http-nio-8080-exec-2] com.myapp.web.api.Exceptionhandler.AppWideExceptionHandler.globalExceptionHandler null javax.persistence.TransactionRequiredException: Для текущего потока нет EntityManager с фактической транзакцией - с а н н О т р Это л я а б л и п р О с Это с с ь р Это м О в Это ь с а л л а т О р г . с п р я н г ж р а м Это В О р к . О р м . дж п а . С час а р Это д И н т я т и М а н а г Это р С р Это а т О р $ С час а р Это д И н т я т и М а н а г Это р я н в О с а т я О н ЧАС а н д л Это р . я н в О к Это ( С час а р Это д И н т я т и М а н а г Это р С р Это а т О р . дж а в а : 2 я 5 ) а т с О м . с в н . п р О Икс и . $ п р О Икс и 8 0 . р Это м О в Это ( В н к н О В н Источник) на com.myapp.web.dal.CrudDAOImpl.delete (CrudDAOImpl.java:67) на com.myapp.web.business.custom.impl.CustomerBOImpl.deleteCustomer (CustomerBOImpl.java:79) в com.myapp.web.api.CustomerController.deleteCustomer(CustomerController.java:116) в sun.reflect.NativeMethodAccessorImpl.invoke0 (собственный метод) в sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) в sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) в java.lang.reflect.Method.invoke(Method.java:498) в org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) в org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) в org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) в org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) в org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal (RequestMappingHandlerAdapter.java:808) в org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) в org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) в org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) в org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) в org.springframework.web.servlet.FrameworkServlet.doDelete(FrameworkServlet.java:931) в javax.servlet.http.HttpServlet.service(HttpServlet.java:687) в org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) в javax.servlet.http.HttpServlet.service(HttpServlet.java:764) в org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) в org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) в org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) в org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) в org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) в org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) в org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) в org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) в org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) в org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) в org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:687) в org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) в org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:359) в org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) в org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) в org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889) в org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1735) в org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) в org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) в org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) в org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) в java.lang.Thread.run(Thread.java:748) Уровень API [*]CustomerController.java пакет com.myapp.web.api; импортировать com.myapp.web.api.util.ApiUtil; импортировать com.myapp.web.business.custom.CustomerBO; импортировать com.myapp.web.dto.CustomerDTO; импортировать com.myapp.web.Exception.IdFormatException; импортировать com.myapp.web.Exception.RecordNotFoundException; импортировать org.springframework.beans.factory.annotation.Autowired; импортировать org.springframework.http.HttpStatus; импортировать org.springframework.http.MediaType; импортировать org.springframework.web.bind.annotation.*; импортировать java.util.List; @CrossOrigin(origins = "http://localhost:8080") @RequestMapping("/api/v1/customers") @RestController общественный класс CustomerController { @Autowired частный клиентBO клиентBO; /** * Получить список всех клиентов. * * @return List Список клиентов. */ @GetMapping (производит = MediaType.APPLICATION_JSON_VALUE) public List getAllCustomers() выдает исключение { вернуть клиентаBO.getAllCustomers(); } /** * Получить клиента по идентификатору клиента. * * @return Объект клиента CustomerDTO. * @throws IdFormatException, если идентификатор не является целым числом. * @throws RecordNotFoundException, если соответствующая запись клиента не найдена, */ @GetMapping(выдает = MediaType.APPLICATION_JSON_VALUE, значение = "/{id:\\d}") public CustomerDTO getCustomerByID(@PathVariable(name = "id") String id) выдает исключение { System.out.println("CustomerID: " + id); Целочисленный идентификатор клиента = ApiUtil.getIntegerId(id); CustomerDTO клиент = customerBO.getCustomerByID(customerID); System.out.println("Результат клиента: " + клиент); /* Если клиент не найден. */ if (customer == null) создать новое RecordNotFoundException(); возврат клиента; } /** * Удаление клиента по идентификатору клиента. */ @ResponseStatus(HttpStatus.NO_CONTENT) @DeleteMapping(value = "/{id:\\d}") public void deleteCustomer(@PathVariable String id) выдает исключение { Целочисленный идентификатор клиента = ApiUtil.getIntegerId(id); System.out.println("Идентификатор клиента: " + идентификатор клиента); customerBO.deleteCustomer(customerID); } } Бизнес-уровень [*]SuperBO.java пакет com.myapp.web.business; общедоступный интерфейс SuperBO { } [*]CustomerBOImpl.java пакет com.myapp.web.business.custom.impl; импортировать com.myapp.web.business.custom.CustomerBO; импортировать com.myapp.web.business.custom.util.mapper.CustomerDTOMapper; импортировать com.myapp.web.dal.custom.CustomerDAO; импортировать com.myapp.web.dto.CustomerDTO; импортировать com.myapp.web.entity.Customer; импортировать ломбок.NoArgsConstructor; импортировать org.springframework.beans.factory.annotation.Autowired; импортировать org.springframework.stereotype.Service; импортировать org.springframework.transaction.annotation.Transactional; импортировать java.util.List; @NoArgsConstructor @Транзакционный @Услуга публичный класс CustomerBOImpl реализует CustomerBO { @Autowired частный CustomerDAO customerDAO; @Autowired частный картограф CustomerDTOMapper; @Override public void deleteCustomer(int customerID) выдает исключение { /* удалить. */ this.customerDAO.delete(customerID); } @Transactional(readOnly = true) @Override public CustomerDTO getCustomerByID (int customerID) выдает исключение { /* получить клиента по идентификатору клиента. */ вернуть this.mapper.getCustomerDTO(this.customerDAO.get(customerID)); } @Transactional(readOnly = true) @Override public List getAllCustomers() выдает исключение { /* получить всех клиентов. */ вернуть this.mapper.getCustomerDTOs(this.customerDAO.getAll()); } } [*]CustomerDTOMapper.java пакет com.myapp.web.business.custom.util.mapper; импортировать com.myapp.web.dto.CustomerDTO; импортировать com.myapp.web.entity.Customer; импортировать org.mapstruct.Mapper; импортировать java.util.List; @Mapper(comComponentModel = "весна") публичный абстрактный класс CustomerDTOMapper { /* -------------------- Клиент -------------------- */ общедоступный абстрактный клиент getCustomer (CustomerDTO customerDTO); общедоступный абстрактный CustomerDTO getCustomerDTO (Клиент-клиент); общедоступный абстрактный список List getCustomerDTOs(List customerList); } Уровень доступа к данным [*]SuperDAO.java пакет com.myapp.web.dal; импортировать javax.persistence.EntityManager; общедоступный интерфейс SuperDAO { EntityManager getEntityManager(); } [*]CrudDAO.java пакет com.myapp.web.dal; импортировать com.myapp.web.entity.SuperEntity; импортировать java.io.Serializable; импортировать java.util.List; общедоступный интерфейс CrudDAO расширяет SuperDAO { /** * сохранение объекта и возврат объекта. * * @return T СуперEntity. */ T save(Tentity) выдает исключение; void update(Tentity) выдает исключение; void delete (ключ PK) выдает исключение; T get(ключ PK) выдает исключение; List getAll() выдает исключение; } [*]CrudDAOImpl.java пакет com.myapp.web.dal; импортировать com.myapp.web.entity.SuperEntity; импортировать javax.persistence.EntityManager; импортировать javax.persistence.PersistenceContext; импортировать java.io.Serializable; импортировать java.lang.reflect.ParameterizedType; импортировать java.util.List; открытый класс CrudDAOImpl реализует CrudDAO { частный окончательный классEntityClass; @PersistenceContext частный EntityManager EntityManager; общественный CrudDAOImpl () { this.entityClass = (Class) (((ParameterizedType) (this.getClass().getGenericSuperclass()))).getActualTypeArguments()[0]); } /** * Этот метод используется для передачи EntityManager классам нижнего уровня, которые расширяют класс CrudDAOImpl. */ общественный EntityManager getEntityManager () { вернуть this.entityManager; } @Override public void delete (ключ K) выдает исключение { this.entityManager.remove(ключ); } @Override public T get(K key) выдает исключение { вернуть this.entityManager.find(this.entityClass, key); } @Override public List getAll() выдает исключение { List resultList = (List) this.entityManager. createQuery("SELECT e FROM " + this.entityClass.getName() + " e").getResultList(); вернуть список результатов; } } [*]CustomerDAO.java пакет com.myapp.web.dal.custom; импортировать com.myapp.web.dal.CrudDAO; импортировать com.myapp.web.entity.Customer; общедоступный интерфейс CustomerDAO расширяет CrudDAO { } [*]CustomerDAOImpl.java пакет com.myapp.web.dal.custom.impl; импортировать com.myapp.web.dal.CrudDAOImpl; импортировать com.myapp.web.dal.custom.CustomerDAO; импортировать com.myapp.web.entity.Customer; импортировать org.springframework.stereotype.Repository; @Репозиторий открытый класс CustomerDAOImpl расширяет CrudDAOImpl реализует CustomerDAO { } Вот что я пробовал. Я попробовал модульное тестирование. Модульный тестовый пример уровня BO и DAO работал как задумано, но когда я проверяю API, отправляя HTTP-запрос с помощью Postman, сохранение, обновление и удаление невозможно выполнить с помощью API.
[*]CustomerDAOImplTest.java ----> ТЕСТ ПРОЙДЕН! ✔
пакет com.myapp.web.dal.custom.impl; импортировать com.myapp.web.WebAppConfig; импортировать com.myapp.web.WebRootConfig; импортировать com.myapp.web.dal.custom.CustomerDAO; импортировать com.myapp.web.entity.Customer; импортировать com.myapp.web.entity.enumeration.GenderTypes; импортировать org.junit.Test; импортировать org.junit.runner.RunWith; импортировать org.springframework.beans.factory.annotation.Autowired; импортировать org.springframework.test.context.ContextConfiguration; импортировать org.springframework.test.context.junit4.SpringJUnit4ClassRunner; импортировать org.springframework.test.context.web.WebAppConfiguration; импортировать org.springframework.transaction.annotation.Transactional; импортировать java.util.List; импортировать статический org.junit.Assert.*; @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(классы = {WebRootConfig.class, WebAppConfig.class}) общественный класс CustomerDAOImplTest { @Autowired частный CustomerDAO customerDAO; @Тест общественный недействительный checkCustomerDAO () { AssertNotNull (customerDAO); } @Транзакционный @Тест public void getCustomerByID() выдает исключение { AssertNotNull (customerDAO); Клиент-клиент = this.customerDAO.get(10); System.out.println("GET Customer Entity: " + клиент); AssertNotNull (клиент); } @Тест public void getAllCustomers() выдает исключение { List customerList = this.customerDAO.getAll(); AssertEquals(2, customerList.size()); } @Транзакционный @Тест public void deleteCustomer() выдает исключение { AssertNotNull(this.customerDAO); /* удалить */ this.customerDAO.delete(3); Клиент customerFromDB = this.customerDAO.get(10); AssertNull (клиентFromDB); } }

[*]CustomerBOImpl.java ----> ТЕСТ ПРОЙДЕН ! ✔
пакет com.myapp.web.business.custom.impl; импортировать com.myapp.web.WebAppConfig; импортировать com.myapp.web.WebRootConfig; импортировать com.myapp.web.business.custom.CustomerBO; импортировать com.myapp.web.dto.CustomerDTO; импортировать com.myapp.web.entity.enumeration.GenderTypes; импортировать org.junit.Test; импортировать org.junit.runner.RunWith; импортировать org.springframework.beans.factory.annotation.Autowired; импортировать org.springframework.test.context.ContextConfiguration; импортировать org.springframework.test.context.junit4.SpringJUnit4ClassRunner; импортировать org.springframework.test.context.web.WebAppConfiguration; импортировать статический org.junit.Assert.assertNotNull; импортировать статический org.junit.Assert.assertNull; @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(classes = {WebRootConfig.class, WebAppConfig.class}) общественный класс CustomerBOImplTest { @Autowired частный клиентBO клиентBO; @Тест общественный недействительный checkCustomerBO () { AssertNotNull (клиентBO); } // @Транзакциональный @Тест общественная недействительность deleteCustomer() выдает исключение { AssertNotNull(this.customerBO); /* удалить */ this.customerBO.deleteCustomer(3); CustomerDTO customerDTOFromDB = this.customerBO.getCustomerByID(10); AssertNull (клиентDTOFromDB); } }

Зависимости pom.xml
javax.servlet javax.servlet-api 4.0.1 предоставлена mysql mysql-connector-java 8.0.27 компилировать org.slf4j slf4j-jdk14 2.0.0-альфа1 компилировать юнит junit 4.13.2 тест commons-валидатор commons-валидатор 1.7 org.mapstruct mapstruct ${org.mapstruct.version} org.projectlombok ломбок 1.18.22 предоставлена org.hibernate hibernate-core 5.6.3.Окончательная кодек-commons commons-кодек 1.15 org.springframework spring-orm 5.3.14 org.apache.commons commons-dbcp2 2.9.0 org.aspectj aspectjrt 1.9.7 org.aspectj aspectjweaver 1.9.7 время выполнения org.springframework spring-webmvc 5.3.15 com.fasterxml.jackson.core привязка данных Джексона 2.13.1 com.fasterxml.jackson.datatype jackson-datatype-jsr310 2.13.1 org.springframework весенний тест 5.3.15 тест Среда разработки [*]Ява 8 [*]Томкэт 9 Я имел в виду следующие вопросы и ответы, но не смог решить проблему. Буду признателен за помощь в исправлении ошибка и понять ошибку.
[*]https://stackoverflow.com/a/32552558/12898581 [*]javax.persistence.TransactionRequiredException: для текущего потока нет EntityManager с фактической транзакцией [*]https://www.wilfriedbarth.com/til/2018- ... nnotation/