Я получаю эту ошибку, когда пытаюсь загрузить изображение в свой проект. Проект выполняется нормально до тех пор, пока ему не потребуется эффективно загрузить изображение в базу данных (я использую postgresql), но этот последний шаг никогда не работает.
Следующий код был обновлен с учетом ответов ниже.
Вот мой контроллер (его часть):
@Autowired
private FileUploadImpl fileUploadImpl;
...
@RequestMapping(value = "publish4" ,method = RequestMethod.POST)
public ModelAndView publish4(@Valid @ModelAttribute("fourthPublicationForm") final FourthPublicationForm form, final BindingResult errors,
@RequestParam("type") String type, @RequestParam("operation") String operation , @RequestParam CommonsMultipartFile[] fileUpload) {
if (errors.hasErrors()) {
//return helloPublish3(form,operation,type);
}
System.out.println("operation: "+ operation);
System.out.println("type: "+ type);
ps.create(form.getTitle(), form.getAddress(), operation, form.getPrice(), form.getDescription(),
type, form.getBedrooms(), form.getBathrooms(), form.getFloorSize(), form.getParking());
if (fileUpload != null && fileUpload.length > 0) {
for (CommonsMultipartFile aFile : fileUpload){
System.out.println("Saving file: " + aFile.getOriginalFilename());
UploadFile uploadFile = new UploadFile();
uploadFile.setAddress(form.getAddress());
uploadFile.setData(aFile.getBytes());
fileUploadImpl.save(uploadFile);
}
}
return new ModelAndView("redirect:/hello/home");
}
Это fileUploadDao в интерфейсе:
public interface FileUploadDao {
void save(UploadFile uploadFile);
}
Это в сервисах:
@Service
public class FileUploadImpl {
@Autowired
private FileUploadDao fileUploadDao;
public FileUploadImpl() {
}
@Transactional
public void save(UploadFile uploadFile) {
fileUploadDao.save(uploadFile);
}
}
Следующее по настойчивости:
@Repository
public class FileUploadDAOImpl implements FileUploadDao {
@Autowired
private SessionFactory sessionFactory;
public FileUploadDAOImpl() {
}
public FileUploadDAOImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void save(UploadFile uploadFile) {
sessionFactory.getCurrentSession().save(uploadFile);
}
}
Я получил это в WebConfig.java (среди прочего)
@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(
new String[] { "ar.edu.itba.paw" }
);
//sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
@Autowired
@Bean(name = "fileUploadDao")
public FileUploadDao getUserDao(SessionFactory sessionFactory) {
return new FileUploadDAOImpl(sessionFactory);
}
@Bean(name = "multipartResolver")
public CommonsMultipartResolver getCommonsMultipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(20971520); // 20MB
multipartResolver.setMaxInMemorySize(1048576); // 1MB
return multipartResolver;
}
@Bean
@Autowired
public HibernateTransactionManager transactionManager(
SessionFactory sessionFactory) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
Еще немного об ошибке:
org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:106)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
at ar.edu.itba.paw.persistence.FileUploadDAOImpl.save(FileUploadDAOImpl.java:25)
at ar.edu.itba.paw.webapp.controller.HelloWorldController.publish4(HelloWorldController.java:260)
Я видел и другие вопросы, на которые ответом было отсутствие использования слова «транзакционный». Я использую здесь эту аннотацию, но не уверен, что она на 100% верна.




Как вы сказали с самого начала, вы перепутали сами слои. Тем не менее, вы могли бы заставить его работать должным образом в вашей ситуации, но давайте немного обсудим вашу реализацию.
FileUploadDao - это DAO или сервис?FileUploadImpl кажется, что вы путаете @Service с @Repository,
возможно, прочтение этого может вам помочь. Репозитории данных Spring, Аннотация службы Springsave, в котором я не могу точно сказать, чего вы хотите достичь. Вы также автоматически подключаете как FileUploadDao, так и SessionFactory, хотя вы хотите реализовать первый и внутри метода, который вы пытаетесь сохранить объект дважды, сначала вызвав save в репозитории (это изначально StackOverflowError, но вам повезло, потому что Spring знает, что автоматизировать), а затем вы пытаетесь второй раз вызвать save на SessionFactory Hibernate, что нарушает абстрактный контракт JPA. Также, если вы заметили, ошибка в опубликованных вами журналах возникает из-за второго сохранения.@Transactional не собирается обсуждать, как это работает, поскольку вы не опубликовали всю конфигурацию приложения. Но опять же, вы можете прочитать это для получения дополнительной информации.Итак, основываясь на примерах, которыми вы поделились, я собираюсь подготовить 2 кейса, которые могут помочь вам понять, что происходит ниже.
Ваш FileUploadImpl становится: FileUploadService
@Service
public class FileUploadService {
@Autowired
private FileUploadDao fileUploadDao;
public FileUploadService() {
}
@Transactional
public void save(UploadFile uploadFile) {
fileUploadDao.save(uploadFile);
}
}
Внутри вашего контроллера вы автоматически подключаете службу (уровень), а не напрямую репозиторий / DAO (уровень). Нет ничего, что вас останавливает, это просто вопрос дизайна (если вы все еще не поняли этого, задайте другой вопрос).
Часть вашего контроллера части
@Autowired
private FileUploadService fileUploadService;
@RequestMapping(value = "publish4" ,method = RequestMethod.POST)
public ModelAndView publish4(@Valid @ModelAttribute("fourthPublicationForm") final FourthPublicationForm form, final BindingResult errors,
@RequestParam("type") String type, @RequestParam("operation") String operation , @RequestParam CommonsMultipartFile[] fileUpload) {
.........
fileUploadService.save(uploadFile);
}
import org.springframework.stereotype.Component;
@Component
public class FileUploadDao {
@Autowired
private SessionFactory sessionFactory;
public FileUpload save(FileUpload obj) {
return sessionFactory.getCurrentSession().save(obj);
}
public FileUpload merge(FileUpload obj) {
return sessionFactory.getCurrentSession().merge(obj);
}
..... delete / update / or custom queries(SQL/JPQL/HQL) can be placed here
}Ваш сервис просто предоставляет эти методы, проверьте разницу, я применяю аннотацию @Transactional к этому слою (опять же, вы можете поместить ее в слой DAO, но, как я уже сказал, это вопрос дизайна).
@Service
public class FileUploadService {
@Autowired
private FileUploadDao fileUploadDao;
public FileUploadService() {
}
@Transactional
public UploadFile save(UploadFile uploadFile) {
fileUploadDao.save(uploadFile);
}
@Transactional
public UploadFile merge(UploadFile uploadFile) {
fileUploadDao.merge(uploadFile);
}
....rest of the methods you want to expose , or combinations of mulitple DAOs
}
Ваш контроллер остается прежним, и это настоящая причина, по которой вам нужны слои.
Спасибо за уделенное время. К сожалению, я не могу заставить это работать. Первая альтернатива выдает то же исключение, а вторая выдает мне исключение сразу после запуска проекта (не удалось внедрить автоматические зависимости ...). Я обновил свой код, предоставив более подробную информацию, возможно, мне что-то еще не хватает.
Я только что обновил свой вопрос с помощью предоставленной вами помощи (первая альтернатива) и кода уровня сохраняемости, который я забыл раньше. Я также добавил webconfig.
Я оставил FileUploadImpl с этим именем, но изменил все, что вы сказали.
@Stackoverflowed в вашем контроллере, какой дао вы подключаете автоматически? Причина из опубликованной, я вижу, что вы явно вводите FileUploadImpl.
Сначала удалите @Transactional из FileUploadDAOImpl.
Соответственно измените базовый пакет,
sessionFactory.setPackagesToScan(
new String[] { "base.package.to.scan" }
);
base.package.to.scan выглядит как недопустимое название базового пакета, измените его на ar.edu.itba.paw.
Чтобы использовать @Transactional, вам нужен менеджер транзакций. Добавьте его в WebConfig
@Bean
@Autowired
public HibernateTransactionManager transactionManager(
SessionFactory sessionFactory) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory());
return txManager;
}
Это может заставить этот код работать, попробуйте.
ОБНОВЛЕНИЕ: Также убедитесь, что в классе WebConfig присутствуют следующие аннотации,
@Configuration
@ComponentScan({"ar.edu.itba.paw"})
@EnableTransactionManagement(mode = AdviceMode.PROXY)
public class WebConfig {
// code
}
Спасибо, базовый пакет точно был неправильным. Я обновил свой код выше, используя ваш ответ. Я все еще получаю то же самое исключение.
Примечание @Stackoverflowed: поскольку вы используете зависимость с автоматическим подключением поля для sessionFactory, нет необходимости в методе getUserDao в WebConfig.java
@Stackoverflowed вы добавили необходимые аннотации в класс WebConfig.java? Пожалуйста, смотрите обновление.
Я добавил @EnableTransactionManagement без режима, потому что я мог разрешить AdviceMode (может быть, мне нужна зависимость или что-то в этом роде?). В любом случае, когда это исключение было исправлено, я получаю новое «org.hibernate.exception.SQLGrammarException: не удалось извлечь ResultSet», но это, вероятно, для другого вопроса. Большое тебе спасибо.
@OldPro Я пробовал там решения, но они, похоже, не работают или, может быть, я их плохо понимаю.