Итак, я обновил приложение с SpringBoot 2.1 до 2.6 и Wicket 8.6 до 9.8, и теперь все работает нормально, кроме загрузки csv-файлов. Я не получаю никакой ошибки, файл создается, как и должен быть, но он не загружается, и я больше не знаю, где искать. Итак, я поделюсь классами кнопки загрузки и самой загрузки. Может быть, у кого-то есть идея.
AjaxФайлСкачать
import java.io.File;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.AbstractAjaxBehavior;
import org.apache.wicket.request.IRequestCycle;
import org.apache.wicket.request.handler.resource.ResourceStreamRequestHandler;
import org.apache.wicket.request.resource.ContentDisposition;
import org.apache.wicket.util.file.Files;
import org.apache.wicket.util.resource.FileResourceStream;
import org.apache.wicket.util.resource.IResourceStream;
// Based on: https://cwiki.apache.org/confluence/display/WICKET/AJAX+update+and+file+download+in+one+blow
public class AjaxFileDownload extends AbstractAjaxBehavior {
private static final long serialVersionUID = -3721931990952363001L;
private File file;
private boolean deleteAfter;
private boolean addAntiCache;
public AjaxFileDownload() {
this(false, true);
}
public AjaxFileDownload(boolean deleteAfter) {
this(deleteAfter, true);
}
public AjaxFileDownload(boolean deleteAfter, boolean addAntiCache) {
super();
this.deleteAfter = deleteAfter;
this.addAntiCache = addAntiCache;
}
// Call this method to initiate the download
public void initiate(AjaxRequestTarget target) {
if (file == null) {
throw new IllegalArgumentException("No file has been provided for download.");
}
String url = getCallbackUrl().toString();
if (addAntiCache) {
url = url + (url.contains("?") ? "&" : "?");
url = url + "antiCache = " + System.currentTimeMillis();
}
// the timeout is needed to let Wicket release the channel
target.appendJavaScript("setTimeout(\"window.location.href='" + url + "'\", 100);");
}
@Override
public void onRequest() {
ResourceStreamRequestHandler handler = new ResourceStreamRequestHandler(getResourceStream(), getFileName()) {
@Override
public void respond(IRequestCycle requestCycle) {
super.respond(requestCycle);
if (deleteAfter) {
Files.remove(file);
}
}
};
handler.setContentDisposition(ContentDisposition.ATTACHMENT);
getComponent().getRequestCycle().scheduleRequestHandlerAfterCurrent(handler);
}
private String getFileName() {
return file.getName();
}
private IResourceStream getResourceStream() {
return new FileResourceStream(new org.apache.wicket.util.file.File(file));
}
// Set file to download
public void setFile(File file) {
this.file = file;
}
}
инициация вызывается этим методом
private AbstractButtonPanel createDownloadTemplateButton(String markupId) {
return new ButtonPanel(markupId) {
@Override
protected void buttonClick(final AjaxRequestTarget target) {
FormExceptionHandler<File> handler = dataHolder -> generateCsvTemplateFile();
File templateDownload = handler.apply(new WicketExceptionDataholder(target, form, log));
fileDownloadBehaviour.setFile(file);
fileDownloadBehaviour.initiate(target);
}
}.withLinkTextKey("downloadTemplateButton.label");
}
КнопкаПанель
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
public abstract class ButtonPanel extends AbstractButtonPanel {
public ButtonPanel(String markupId) {
super(markupId);
}
@Override
protected AjaxLink<Void> createAbstractLink(String markupId) {
return new AjaxLink<>(markupId) {
@Override
public void onClick(AjaxRequestTarget target) {
buttonClick(target);
}
};
}
protected abstract void buttonClick(AjaxRequestTarget target);
}
АннотацияКнопка
import com.xyz.uof.frontend.web.bootstrap.css.BootstrapCssEnum;
import com.xyz.uof.frontend.web.bootstrap.css.BootstrapCssEnum.BUTTON;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.apache.wicket.Component;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.markup.html.WebComponent;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.AbstractLink;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
public abstract class AbstractButtonPanel extends Panel {
/**
* Change the button to be a link, btn-primary, or what else
*/
private String buttonSizeClass = BUTTON.SIZE_SMALL;
private String cssClass = BootstrapCssEnum.BUTTON.PRIMARY;
private String linkTextKey;
private String buttonName = "submitButton"; // default
private IModel<Boolean> visibleModel = Model.of(true);
private IModel<Boolean> enabledModel = Model.of(true);
private String iconClass;
private boolean spinnerActive = false;
public AbstractButtonPanel(String markupId) {
super(markupId);
setOutputMarkupId(true);
}
@Override
protected void onInitialize() {
super.onInitialize();
add(createLink("link"));
}
@Override
protected void onConfigure() {
super.onConfigure();
setVisibilityAllowed(visibleModel.getObject());
setEnabled(enabledModel.getObject());
}
private AbstractLink createLink(String markupId) {
AbstractLink ajaxLink = createAbstractLink(markupId);
ajaxLink.add(new AttributeAppender("class", buttonSizeClass + " " + cssClass, " "));
ajaxLink.add(createSpinner("spinner", ajaxLink));
ajaxLink.add(createLabel("label"));
ajaxLink.add(createIcon("labelIcon"));
ajaxLink.get("labelIcon").add(new AttributeAppender("class", iconClass, " "));
return ajaxLink;
}
protected abstract AbstractLink createAbstractLink(String markupId);
private Component createSpinner(String markupId, AbstractLink ajaxLink) {
if (spinnerActive) {
ajaxLink.add(new AttributeAppender("onClick", String.format("document.getElementById('%s').childNodes[1].className = 'spinner-grow spinner-grow-sm';", ajaxLink.getMarkupId())));
}
return new WebComponent(markupId) {
@Override
protected void onConfigure() {
super.onConfigure();
getParent().getId();
setVisibilityAllowed(spinnerActive);
}
};
}
private Label createLabel(String markupId) {
// Use this model to handle null linkTextKey.
// Helps to have buttons with glyphicons only
return new Label(markupId, () -> StringUtils.isNotBlank(linkTextKey) ? getString(linkTextKey) : "") {
@Override
protected void onConfigure() {
super.onConfigure();
setVisibilityAllowed(StringUtils.isNotBlank(linkTextKey));
}
};
}
private Component createIcon(String markupId) {
return new WebComponent(markupId) {
@Override
protected void onConfigure() {
super.onConfigure();
setVisibilityAllowed(Optional.ofNullable(iconClass).isPresent());
}
};
}
public AbstractButtonPanel withButtonSizeClass(String buttonSizeClass) {
this.buttonSizeClass = buttonSizeClass;
return this;
}
public AbstractButtonPanel withCssClass(String cssClass) {
this.cssClass = cssClass;
return this;
}
// Important for Selenium
public AbstractButtonPanel withName(String... buttonName) {
StringBuilder sb = new StringBuilder();
for (String currentSplit : buttonName) {
sb.append(currentSplit);
}
sb.append(this.buttonName);
this.buttonName = sb.toString();
return this;
}
public AbstractButtonPanel withLinkTextKey(String linkTextKey) {
this.linkTextKey = linkTextKey;
return this;
}
public AbstractButtonPanel withVisibleModel(IModel<Boolean> visibleModel) {
this.visibleModel = visibleModel;
return this;
}
public AbstractButtonPanel withEnabledModel(IModel<Boolean> enabbledModel) {
this.enabledModel = enabbledModel;
return this;
}
public AbstractButtonPanel withIconName(String iconName) {
this.iconClass = iconName;
return this;
}
public AbstractButtonPanel withSpinner(boolean spinnerActive) {
this.spinnerActive = spinnerActive;
return this;
}
}
Итак, проблема была в этой части
target.appendJavaScript("setTimeout(\"window.location.href='" + url + "'\", 100);");
Javascript был заблокирован, и мне нужно было разблокировать его в другом классе, который расширяет WicketBootSecuredWebApplication, как это
@Override
protected void init() {
super.init();
getCspSettings().blocking().disabled();
}
}
Я не могу сказать, почему ваш код не работает, но вы можете сравнить его с официальными примерами: github.com/apache/wicket/blob/master/wicket-examples/src/main/…. С некоторых пор org.apache.wicket.extensions.ajax.AjaxDownloadBehavior является частью модуля wicket-extensions.