Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for processing HtmxResponse in the Model and as an Argument #128

Merged
merged 4 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,41 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;

public class HtmxHandlerInterceptor implements HandlerInterceptor {

private final ObjectMapper objectMapper;
private final HtmxResponseHandlerMethodReturnValueHandler htmxResponseHandlerMethodReturnValueHandler;

public HtmxHandlerInterceptor(ObjectMapper objectMapper) {
public HtmxHandlerInterceptor(ObjectMapper objectMapper, HtmxResponseHandlerMethodReturnValueHandler htmxResponseHandlerMethodReturnValueHandler) {
this.objectMapper = objectMapper;
this.htmxResponseHandlerMethodReturnValueHandler = htmxResponseHandlerMethodReturnValueHandler;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
if(modelAndView != null) {
modelAndView.getModel().values().forEach(
value ->{
if(value instanceof HtmxResponse) {
buildAndRender((HtmxResponse) value, modelAndView, request, response);
} else if (value instanceof HtmxResponse.Builder) {
buildAndRender(((HtmxResponse.Builder) value).build(), modelAndView, request, response);
}
});
}
}

private void buildAndRender(HtmxResponse htmxResponse, ModelAndView mav, HttpServletRequest request, HttpServletResponse response) {
View v = htmxResponseHandlerMethodReturnValueHandler.toView(htmxResponse);
try {
v.render(mav.getModel(), request, response);
htmxResponseHandlerMethodReturnValueHandler.addHxHeaders(htmxResponse, response);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,21 @@ public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HtmxHandlerInterceptor(objectMapper));
registry.addInterceptor(new HtmxHandlerInterceptor(objectMapper, createHtmxReponseHandler()));
}

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new HtmxHandlerMethodArgumentResolver());
resolvers.add(new HtmxResponseHandlerMethodArgumentResolver());
}

@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
handlers.add(new HtmxResponseHandlerMethodReturnValueHandler(resolver.getObject(), locales, objectMapper));
handlers.add(createHtmxReponseHandler());
}

private HtmxResponseHandlerMethodReturnValueHandler createHtmxReponseHandler() {
return new HtmxResponseHandlerMethodReturnValueHandler(resolver.getObject(), locales, objectMapper);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.github.wimdeblauwe.htmx.spring.boot.mvc;

import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

public class HtmxResponseHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(HtmxResponse.Builder.class);
}

@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
HtmxResponse.Builder htmxResponseBuilder = HtmxResponse.builder();
if(mavContainer != null) {
mavContainer.addAttribute(htmxResponseBuilder);
}
return htmxResponseBuilder;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void handleReturnValue(Object returnValue,
addHxHeaders(htmxResponse, webRequest.getNativeResponse(HttpServletResponse.class));
}

private View toView(HtmxResponse htmxResponse) {
View toView(HtmxResponse htmxResponse) {
wimdeblauwe marked this conversation as resolved.
Show resolved Hide resolved

Assert.notNull(htmxResponse, "HtmxResponse must not be null!");

Expand All @@ -74,7 +74,7 @@ private View toView(HtmxResponse htmxResponse) {
};
}

private void addHxHeaders(HtmxResponse htmxResponse, HttpServletResponse response) {
void addHxHeaders(HtmxResponse htmxResponse, HttpServletResponse response) {
addHxTriggerHeaders(response, HtmxResponseHeader.HX_TRIGGER, htmxResponse.getTriggersInternal());
addHxTriggerHeaders(response, HtmxResponseHeader.HX_TRIGGER_AFTER_SETTLE, htmxResponse.getTriggersAfterSettleInternal());
addHxTriggerHeaders(response, HtmxResponseHeader.HX_TRIGGER_AFTER_SWAP, htmxResponse.getTriggersAfterSwapInternal());
Expand Down