#java #multithreading #spring-boot #freemarker
#java #многопоточность #spring-boot #freemarker
Вопрос:
У меня есть эти HTML-формы на index.htm
:
<form action="/generate/report1" method="get">
<input name="name" type="text" value="test"/>
<input type="submit" value="generate report1">
</form>
<form action="/generate/report2" method="get">
<input name="name" type="text" value="test"/>
<input type="submit" value="generate report2">
</form>
<form action="/generate/report3" method="get">
<input name="name" type="text" value="test"/>
<input type="submit" value="generate report3">
</form>
И в контроллере у меня есть 3 метода для создания этих отчетов
@RequestMapping(value = "/generate/report1", method = RequestMethod.GET)
public ModelAndView generate(@RequestParam String name) throws NurException, IOException {
ModelAndView index = new ModelAndView("index");
billService.createReport1(name);
index.addObject("message", "Success");
return index;
}
@RequestMapping(value = "/generate/report2", method = RequestMethod.GET)
public ModelAndView generateCorrect(@RequestParam String name) throws NurException, IOException {
ModelAndView index = new ModelAndView("index");
billService.createReport2(name);
index.addObject("message", "Success");
return index;
}
@RequestMapping(value = "/generate/report3", method = RequestMethod.GET)
public ModelAndView generateTmc(@RequestParam String name) throws NurException, IOException {
ModelAndView index = new ModelAndView("index");
billService.createReport3(name);
index.addObject("message", "Success");
return index;
}
Каждый метод billService
генерирует отчеты и сохраняет их в формате PDF. Это очень длительный процесс (10-20 минут), и страница в браузере зависает.
Мне нужно следующее: если пользователь нажимает кнопку generateReport1, он должен иметь возможность нажать и другую кнопку generateReport2, и будут работать два процесса.
Как я могу это сделать? Я думаю, мне нужно генерировать каждый процесс в новом потоке, но, может быть, в Spring Boot эта работа другая?
Комментарии:
1. Рассматривали ли вы асинхронные запросы? Веб-сокеты? Проблема в том, что ваши методы занимают слишком много времени. Таким образом, вместо этого вы должны отделить это с помощью компонента с отслеживанием состояния (с привязкой к сеансу). Затем это может быть опрошено / запрошено интерфейсом.
Ответ №1:
Мне нужно следующее: если пользователь нажимает кнопку generateReport1, он должен иметь возможность нажать и другую кнопку generateReport2, и будут работать два процесса.
Я бы использовал пул потоков для запуска генерации в фоновом режиме, что позволяет веб-странице сообщать «Обработка начата. Обновите эту страницу, чтобы проверить результаты «. Код для выполнения фоновой обработки может быть примерно следующим:
private final ExecutorService threadPool = Executors.newFixedThreadPool(1);
// you should make this class a DisposableBean
public void destroy() {
// shutdown the pool
threadPool.shutdown();
}
// this is similar to generateReport2
public void generateReport1() {
// submit the generator to a background thread
threadPool.submit(new Runnable() {
public void run() {
// do the actual generation in the thread
}
});
}
Это заботится о фоновом потоке, но это не объясняет, как веб-пользователь (который запускается в другом потоке) увидит результаты, которые были созданы в фоновом режиме. Есть несколько способов, которыми вы можете это сделать.
- Вы могли бы отправить им по электронной почте ссылку на сгенерированный PDF-файл, который сохраняется в файловой системе веб-сервера или что-то в этом роде.
- Вы могли бы поместить a
AtomicReference<PdfHolder>
в сеанс пользователя, а затем сгенерировать запись в атомарную ссылку, когда это будет сделано. Затем веб-страница будет искатьAtomicReference
значение, отличное от null. - Вы могли бы поместить некоторый UUID в сеанс пользователя и передать тот же UUID генерирующему потоку, который запишет файл на диск под этим именем. Затем веб-страница будет искать существующий файл.