I'm trying to create a Thymeleaf dialect processor which performs a ServletDispatcher.include. I have extended the AbstractElementTagProcessor and overridden the doProcess method. The relevant code fragment is:
#Override
protected void doProcess(final ITemplateContext context, final IProcessableElementTag tag, final IElementTagStructureHandler structureHandler) {
ServletContext servletContext = null; // TODO: get servlet context
HttpServletRequest request = null; // TODO: get request
HttpServletResponse response = null; // TODO: get response
// Retrieve dispatcher to component JSP view
RequestDispatcher dispatcher = servletContext.getRequestDispatcher("/something");
// Create wrapper (acts as response, but stores output in a CharArrayWriter)
CharResponseWrapper wrapper = new CharResponseWrapper(response);
// Run the include
dispatcher.include(request, wrapper);
String result = wrapper.toString();
// Create a model with the returned string
final IModelFactory modelFactory = context.getModelFactory();
final IModel model = modelFactory.parse(context.getTemplateData(), result);
// Instruct the engine to replace this entire element with the specified model
structureHandler.replaceWith(model, false);
I wrote similar code in the past in the form of a custom JSP tag. Problem is: I don't know how to access the ServletContext, HttpServletRequest and the HttpServletResponse!
Can this be done at all, or should I just accept that Thymeleaf is too good at hiding the HTTP context?
You can access request (by using #request object that gives you the direct access to javax.servlet.http.HttpServletRequest object) parameters and session (with #session object that gives you direct access to the javax.servlet.http.HttpSession object) attributes directly in Thymeleaf views:
${#request.getAttribute('foo')}
${#request.getParameter('foo')}
${#request.getContextPath()}
${#request.getRequestName()}
<p th:if="${#request.getParameter('yourParameter') != null
th:text="${#request.getParameter('yourParameter')}"}">Request Param</p>
${#session.getAttribute('foo')}
${#session.id}
${#session.lastAccessedTime}
<p th:if="${session != null}"> th:text="${session.yourAttribute}"</p>
Read more here.
I found myself with a very similar requirement of accessing the request from an implementation of IExpressionObjectFactory.
The way i solved it (following #Sebastian Marsching advise in a previous comment) is by accessing the objects registered in IExpressionContext that are available from the view in the context of template evaluation (all those objects described in Appendix A and Appendix B of thymeleaf documentation), so you have access to request, response, servletContext and many other utility objects.
Speaking in code:
IExpressionObjects expressionObjects = context.getExpressionObjects();
HttpServletRequest request = (HttpServletRequest)expressionObjects.getObject("request");
There is also an expressionObjects.getObjectNames() method you can call to get a Set<String> with the names of all registered objects, which in my case gives the following list:
[i18nutils, ctx, root, vars, object, locale, request, response, session,
servletContext, conversions, uris, calendars, dates, bools, numbers, objects,
strings, arrays, lists, sets, maps, aggregates, messages, ids, execInfo,
httpServletRequest, httpSession, fields, themes, mvc, requestdatavalues]
Related
I am using Spring Boot 1.5.3.RELEASE and using a Controller that takes a MultipartFile with some other information as arguments and returns a file.
Now I am facing the org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException when the file exceeds the maximum Sizes.
spring.http.multipart.maxFileSize=17728640
spring.http.multipart.maxRequestSize=17728640
This works well but i need a custom Response and actually the Exception is throwed only at server side before the method call.
Can anyone tell me how can I define a Custom Error Handler that handles this exception and response something like ResponseEntity.status(HttpStatus.CONFLICT).body("size_exceeded")
My Method:
#SuppressWarnings("rawtypes")
#RequestMapping(value = "/{Id}/attachments", method = RequestMethod.POST)
public ResponseEntity addTaskAttachment(#RequestParam("file") MultipartFile file, #PathVariable Long Id,
#CurrentUser User currentUser) {
// Some code here
ResponseEntity.status(HttpStatus.OK).body(attachmentAsByteArray);
}
You are correct in your observation that an Exception Handler with #RestControllerAdvice wouldn't work for multi part exceptions and reason being MultipartFile parsing & validation step preceding the mapping resolver step.
As advised in first accepted answer by geoand for this SO question here , you need to define and register an ErrorController.
Also, note that as already mentioned in that answer , Spring Boot already defines a BasicErrorController that you can extend to add new content types to return a JSON etc ( since default is text/html ) by adding a new public method with #RequestMapping & #Produces .
Is it possible to write just a single attribute to the original session without using <private-session-attributes>false</private-session-attributes> with Liferay 6.2.10 and Liferay-Faces-Bridge 3.2.4?
In a JSF-bean / portlet we configure a export file that must be downloadable via a servlet (inside the same WAR).
We want to share one specific Object via the session to get used by some JSTL-magic inside the portal.
I have found no other way than setting <private-session-attributes>false</private-session-attributes>, but that pollutes the session with lots of JSF-specific and even more portlet-specific objects that no one needs in the user-global session. As most portlets in that war need to communicate I would either have to switch all to public session attributes or use IPC.
I tried several ways that only yield positive results while not using private session attributes.
ServiceContextThreadLocal.getServiceContext().getRequest().getSession().setAttribute("SERVICE_CONTEXT", true);
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
// Does not matter which way
// PortletSession portletSession = (PortletSession)externalContext.getSession(false);
PortletSession portletSession = ((PortletRequest) externalContext.getRequest()).getPortletSession();
portletSession.setAttribute("PORTLET_SESSION_PORTLET_SCOPE", true, PortletSession.PORTLET_SCOPE);
portletSession.setAttribute("PORTLET_SESSION_APPLICATION_SCOPE", true, PortletSession.APPLICATION_SCOPE);
HttpServletRequest httpServletRequest = PortalUtil.getHttpServletRequest((PortletRequest) externalContext.getRequest());
httpServletRequest.getSession().setAttribute("EXTERNAL_CONTEXT_SERVLET_REQUEST_SESSION", true);
HttpServletRequest outerRequest = PortalUtil.getOriginalServletRequest(httpServletRequest);
outerRequest.getSession().setAttribute("EXTERNAL_CONTEXT_SERVLETS_SERVLET_REQUEST", true);
Other options that I would like to avoid would be:
use a javax.servlet.Filter with a ThreadLocal
save the generated document (or export configuration) to a database
transport the configuration via the client by re-posting it to the export servlet.
This answer suggests to use the portletSession with ApplicationScoped variables, but I couldn't get the PortletSession.
With setting <private-session-attributes>false</private-session-attributes> I get the following attributes set in the original session:
TEST_WITH_EXTERNAL_CONTEXT_SERVLET_REQUEST_SESSION
TEST_WITH_PORTLET_SESSION_APPLICATION_SCOPE
TEST_WITH_SERVICE_CONTEXT
war_app_name_whatever?TEST_WITH_PORTLET_SESSION_PORTLET_SCOPE
and a great number of other objects (>50) visible in the global users session.
Has anyone a good idea how to set just one session attribute?
Unwrapping the request until reaching a class that does not extend javax.servlet.http.HttpServletRequestWrapper solves the problem.
The request is kindly stored by Liferay and available via ServiceContextThreadLocal.getServiceContext().getRequest().
Liferays PortalUtil just unwraps if the request wrapper is in a package that starts with "com.liferay." and therefore does not work if a custom request wrapper is used.
public static <Type, ValueType extends Type> void setOnOriginalSession(Class<Type> type, ValueType value) {
HttpServletRequest request = ServiceContextThreadLocal.getServiceContext().getRequest();
HttpServletRequest originalRequest = unwrapOriginalRequest(request);
HttpSession originalSession = originalRequest.getSession();
String attributeNameForType = getAttributeNameForType(type);
originalSession.setAttribute(attributeNameForType, value);
}
private static HttpServletRequest unwrapOriginalRequest(HttpServletRequest request) {
while (request instanceof HttpServletRequestWrapper) {
HttpServletRequestWrapper httpServletRequestWrapper = (HttpServletRequestWrapper) request;
request = (HttpServletRequest) httpServletRequestWrapper.getRequest();
}
return request;
}
`I need to contact an API which requires that every request contain the signature of all parameters and url + nonce.
Example:
#GET("/users/{type}")
public void getUsers(
#Path("type") String type,
#Query("sort") boolean sort)
I should add a X-Signature header with contains signature(nonce+"/users/"+type+"sort="+sort).
I thought I could do this with a RequestInterceptor's addHeader(String name, String value) but I can`t as the signature varies for every request.
Is there a smart way to do this with Retrofit or will I just have to manually sign every request?
Am I right in thinking that your signature is generated from [nonce]+[path]+[query params]
You could look at implementing a custom client and passing this into your RestAdapter.Builder().setClient(new CustomClient) method.
Something like CustomClient extends OkClient and then override the execute(Request) method. You will need to create a new Request object and pass that to super.execute(updatedRequest).
#Override
public Response execute(Request request) throws IOException {
List<Header> headers = new ArrayList<>();
// do work here to parse the request.getUrl() and extract path/params and generate the signature
headers.addAll(request.getHeaders());
headers.add(new Header("X-Signature", "signature"));
Request updated = new Request(request.getMethod(), request.getUrl(), headers, request.getBody());
return super.execute(updated);
}
If however there is no consistency to the generation of the signature then you will need to create the signature manually and add a #Header value in your call to your client.
I need to pass a bean object from MVC to webFlow. Currently, I am achieving it this way:
Storing my bean object as request attribute in controller.
Forwarding to flow.
Accessing the object from flowRequestContext on-start of my flow and setting it in flowScope.
#RequestMapping(value = "/ProcessUser", method=RequestMethod.POST)
public String processForm(LoginUser loginUser, HttpServletRequest request){
....
request.setAttribute("registrationDetails", registrationDetails);
return "forward:/chineseFlow"; //Call to flow
}
chineseFlow.xml
<on-start>
<evaluate expression="userDetailsService.getRegistrationDetails(flowRequestContext)" result="flowScope.registrationDetails"/>
</on-start>
UserDetailsService
public RegistrationDetails getRegistrationDetails(RequestContext requestContext){
HttpServletRequest httpRequest = (HttpServletRequest) requestContext.getExternalContext().getNativeRequest();
RegistrationDetails registrationDetails = (RegistrationDetails)httpRequest.getAttribute("registrationDetails");
return registrationDetails;
}
I don't want to pass multiple request parameters as input to my flow. Is this the correct way to pass the bean to SWF or is there any other better way to achieve the same?
There are not many options. Proper way would be to redesign your application so that whole process happens within the same flow, then you can store your values in flowscope to begin with. The only alternatives would be either a request attribute (which you are doing already), or session-scoped bean/session attribute. Out of these request attribute(s) is preferred as otherwise you will end up polluting your session scope, and introduce potential bugs that stem from leftover values in session scope.
I have the following web service:
[ScriptService]
public class Handler : WebService {
[WebMethod]
public void method1() {
string json = "{ \"success\": true }";
System.Web.HttpContext.Current.Response.Write(json);
}
[WebMethod]
public object method2(Dictionary<string, object> d) {
Dictionary<string, object> response = new Dictionary<string, object>();
response.Add("success", true);
return response;
}
}
The first method accepts a traditional html form post and response writes a JSON string to the page. The second method accepts a JSON value posted via AJAX and returns a serialized object.
Both these methods work fine on their own but when put together in the same web service I get this error when calling method1:
System.IndexOutOfRangeException: Index was outside the bounds of the array.
When I remove the arguments from method2 they work.
Can anyone suggest why this is happening?
Edit:
The problem spans from the argument type of method2. If I change it to a string or simple data type it works fine. As Joel suggests it's probably because Dictionaries can't be serialized. This doesn't seem to affect my requests sent by ajax and only breaks direct form posts to this handler. Therefore my workaround is to put the form post handlers in a separate file by themselves. Not ideal but works for my application.
Dictionaries are not serializable. Hiding it behind an object doesn't do anything for you. You must first convert your dictionary to an array or some other serializable object before sending it out.
Why isn't there an XML-serializable dictionary in .NET?
http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx
http://www.tanguay.info/web/index.php?pg=codeExamples&id=333