spring Java config for excel view resolver - spring

I have a spring java config based web app with (jsp) view resolver.
Now i want to show a excel sheet with some data when user clicks on excel icon in app.
All over internet i only found xml based spring config for excel view with which i am not familiar with.
I decoded to some extent and came pretty close to get my task done. Below is what i got.
I have similar controller and Homepage following the below link:
http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch17s06.html
Controlle Code:
#Controller
public class ExcelController extends AbstractController {
#Override
#RequestMapping(value = "/Excel", method = RequestMethod.POST)
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
BufferedReader in = null;
try {
URL oracle = new URL("example.com");
URLConnection yc =null;
yc = oracle.openConnection();
in = new BufferedReader(
new InputStreamReader(
yc.getInputStream()));
}
catch(Exception e){
System.err.println(e);
}
Map map = new HashMap();
map.put("input", in);
return new ModelAndView("xl", map);
}
}
View Code:
public class ExcelReportView extends AbstractExcelView{
#Override
protected void buildExcelDocument(Map model, HSSFWorkbook workbook,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
HSSFSheet sheet;
HSSFRow row;
HSSFCell cell;
try {
BufferedReader in = (BufferedReader) model.get("input");
sheet=workbook.createSheet("spring");
String inputLine;
int rowNum =0;
while ((inputLine = in.readLine()) != null) {
row = sheet.createRow(rowNum++);
String[] coloumns = inputLine.split("\t");
int cellNum =0;
for(String coloumn: coloumns){
cell = row.createCell(cellNum++);
cell.setCellValue(coloumn);
}
System.out.println(inputLine);
}
in.close();
System.out.println("Excel written successfully..");
} catch (IOException e) {
e.printStackTrace();
}
}
}
view.properties
xl.class=package.ExcelReportView
WebAppConfig.java
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "package")
public class WebAppContextConfig extends WebMvcConfigurerAdapter {
// Resolve logical view names to .jsp resources in /WEB-INF/views directory
#Bean
public InternalResourceViewResolver configureInternalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/scripts/**").addResourceLocations(
"/scripts/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/img/**").addResourceLocations("/img/");
}
}
Front end Code:
function AjaxCallForExcel(){
$.ajax({
type: 'POST',
url: location.href + '/Excel',
data: ({name:name })
});
}
Below is what i see in logs:
DispatcherServlet with name 'appServlet' processing POST request for [/App/Excel]
Looking up handler method for path /App/Excel
Returning handler method [protected org.springframework.web.servlet.ModelAndView package.ExcelController.handleRequestInternal(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.lang.Exception]
Returning cached instance of singleton bean 'excelController'
Invoking afterPropertiesSet() on bean with name 'xl'
Rendering view [org.springframework.web.servlet.view.JstlView: name 'xl'; URL [**/WEB-INF/jsp/xl.jsp**]] in DispatcherServlet with name 'appServlet'
Added model object 'org.springframework.validation.BindingResult.input' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'xl'
Added model object 'input' of type [java.io.BufferedReader] to request in view with name 'xl'
Forwarding to resource [/WEB-INF/jsp/xl.jsp] in InternalResourceView 'xl'
Successfully completed request
I dont know how to avoid it from forwarding it to xl.jsp. I am sure view resolver is making it into jsp view. Can someone point how can i fix it.
EDIT
I saw this xml equivalent config online. Not sure how to make it java config:
<bean id="excelViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="order" value="1"/>
<property name="location" value="/WEB-INF/views.xml"/>
</bean>
i tried converting it the below way:
#Bean
public XmlViewResolver configureXmlViewResolver(){
XmlViewResolver resolver = new XmlViewResolver();
resolver.setOrder(1);
resolver.setLocation(**WHAT SHOULD BE HERE**);
}
I dont know what to put in location. I cant give string. i dont have views.xml as i am use java configs
Edit(Here is my code after making changes as you said)
public class ExcelReportView extends AbstractExcelView{
BufferedReader in;
ExcelReportView(BufferedReader in){
this.in = in;
}
#Override
protected void buildExcelDocument(Map model, HSSFWorkbook workbook,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
HSSFSheet sheet;
HSSFRow row;
HSSFCell cell;
response.setHeader("Content-Type", "application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=MyExcelSpreadsheet.xls");
try {
//BufferedReader in = (BufferedReader) model.get("input");
sheet=workbook.createSheet("spring");
String inputLine;
int rowNum =0;
while ((inputLine = in.readLine()) != null) {
row = sheet.createRow(rowNum++);
String[] coloumns = inputLine.split("\t");
int cellNum =0;
for(String coloumn: coloumns){
cell = row.createCell(cellNum++);
cell.setCellValue(coloumn);
}
System.out.println(inputLine);
}
in.close();
System.out.println("Excel written successfully..");
} catch (IOException e) {
e.printStackTrace();
}
OutputStream outStream = null;
try {
outStream = response.getOutputStream();
workbook.write(outStream);
outStream.flush();
} finally {
outStream.close();
}
}
}
Controller Code:
#Controller
public class ExcelController {
#RequestMapping(value = "/Excel", method = RequestMethod.POST)
protected ModelAndView generateCSV(HttpServletRequest request,
HttpServletResponse response) throws Exception {
BufferedReader in = null;
try {
URL oracle = new URL("http://service.com");
URLConnection yc =null;
yc = oracle.openConnection();
in = new BufferedReader(
new InputStreamReader(
yc.getInputStream()));
}
catch(Exception e){
System.err.println(e);
}
ModelAndView mav = new ModelAndView();
mav.setView(new ExcelReportView( in));
return mav;
}
}
Log output:
DispatcherServlet with name 'appServlet' processing POST request for [/App/Excel]
Looking up handler method for path /App/Excel
Returning handler method [protected org.springframework.web.servlet.ModelAndView com.package.ExcelController.generateCSV(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.lang.Exception]
Returning cached instance of singleton bean 'excelController'
Rendering view [com.package.controllers.ExcelReportView: unnamed] in DispatcherServlet with name 'appServlet'
Created Excel Workbook from scratch
Title Id required
Excel written successfully..
Successfully completed request
EDIT:
Response Header:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Pragma: private
Cache-Control: private, must-revalidate
Content-Disposition: attachment; filename=MyExcelSpreadsheet.xls
Content-Type: application/octet-stream;charset=ISO-8859-1
Content-Language: en-US
Transfer-Encoding: chunked
Date: Tue, 12 Mar 2013 16:36:52 GMT

You can return a ModelAndView from your controller method, setting the View to an instance of AbstractExcelView. Then you don't need to mess with your XML at all.
Edit: Add some additional info:
I have done the custom View approach many times to handle CSV downloads.
First, you need to create an instantiation of the AbstractExcelView. You would do so by overwriting the buildExcelDeocument() method. You will need the POI libraries, as I believe it is required. For example:
#Override
public void buildExcelDocument(Map<String, Object> model, HSSFWorkbook workbook,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
// Set the headers
response.setHeader("Content-Type", "application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=MyExcelSpreadsheet.xls");
// Here is where you will want to put the code to build the Excel spreadsheet
OutputStream outStream = null;
try {
outStream = response.getOutputStream();
workbook.write(outStream);
outStream.flush();
} finally {
outStream.close();
}
}
Next you need to modify the Controller method
#RequestMapping(params = "actionMethod="+Constants.ACTION_METHOD_REPORT)
public ModelAndView generateCSV(
#ModelAttribute(Constants.REPORT_FORMBEAN_MODEL_ATTRIBUTE) FormBean formBean,
ModelAndView mav,
HttpServletRequest request,
HttpServletResponse response) {
mav.setView(new MyExcelView( /* modify your constructor to pass in your data so the view can build the output */ ));
return mav;
}
There is no need to edit your context XML, modify how your beans are wired together, create any services, or anything. Simply create an instance of your custom View, pass in whatever you need to in order to build the spreadsheet, then set the view on the ModelAndView. Simple as that.
EDIT - You need to do this...
You need to change your AJAX call so that you can tell if its done or had an error. You are flying blind right now:
function AjaxCallForExcel(){
$.ajax({
type: 'POST',
url: location.href + '/Excel',
data: ({name:name }),
complete: function(jqXHR,textStatus ) {
alert("Complete: "+textStatus );
},
error: function(jqXHR,textStatus,errorThrown ) {
alert("Status: "+textStatus+"\nerror: "+errorThrown );
}
});
}

Related

Spring MVC, redirect to error after Rest call exception

I'm performing a Rest request in one of my controllers and I'd like to redirect to my error view if the request went wrong (404, 503 ...)
My controller calls this function :
public String functionTest(){
String date, res;
String url = "myRestUrl/{param}";
Map<String, String> uriParams = new HashMap<>();
uriParams.put("param", "param");
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url);
HttpEntity<String> request = new HttpEntity<>(createHeaders());
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new RestErrorHandler());
ResponseEntity<String> response = restTemplate.exchange(builder.buildAndExpand(uriParams).toUri(), HttpMethod.GET, request, String.class);
res= response.getBody().getMyResult();
return res;
}
And here is my Rest error handler :
public class RestErrorHandler extends DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
//Here I need to use a ModelAndView to redirect to error view but I'm not anymore in my controller
}
}
I guess I'm doing it wrong, do you have any solutions ?
Here is a rather simplistic way to achieve what you need. If you would like more control/flexibility, refer to this Spring blog article.
In your (client) RestErrorHandler:
public class RestErrorHandler extends DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response)
throws IOException {
// Do some stuff here ...
// This could be your own exception, for example.
throw new IOException();
}
}
Then in your controller (or refer to the article above if you want other options):
// Your requestMappings here ...
#ExceptionHandler(Exception.class)
public ModelAndView handleError(HttpServletRequest req, Exception ex) {
ModelAndView mav = new ModelAndView();
// Do stuff and redirect to your error view.
return mav;
}
EDIT: Another solution would be to catch Spring's RestClientException, which is a RuntimeException thrown by RestTemplate when it encounters an error:
try {
restTemplate.exchange(...);
} catch (RestClientException ex) {
// Do stuff here ...
}

Sending a MultipartFile as a Request Param to REST server using Angular2

I need to upload a photo to the server which has been written using Spring Boot. For the front end which sends the request I use Angular2.
This is my API which accepts the HTTP request. It works fine. (I tested it using Postman)
#RequestMapping(method = RequestMethod.POST, value = "/tender/save-new/save-photo")
public ResponseEntity<?> uploadPhoto(#RequestParam("file") MultipartFile file){
if (file.isEmpty()) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage("DEBUG: Attached file is empty");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.NOT_FOUND);
}
String returnPath = null;
try {
// upload stuff
} catch (IOException e) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage(e.getMessage());
return new ResponseEntity<ErrorResponse> (errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<String>(returnPath, HttpStatus.OK);
}
I am not sure how should I write the code in Angular2 to call the server.
Following is what I have come up with.
savePhoto(photoToSave: File) {
let formData: FormData = new FormData();
formData.append('file', photoToSave);
let savedPath = this._http
.post(this._endpointUrl + "tender/save-new/save-photo", formData)
.map(
res => {
return res.json();
}
)
.catch(handleError);
return savedPath;
}
As you can see, I append the 'file' parameter to the form data before sending it. Server method accepts the RequestParam as 'file'.
But, in the server log, I get following error.
org.springframework.web.multipart.MultipartException: Current request
is not a multipart request at
org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:190)
Note that I haven't declared a CommonsMultipartResolver bean since SprinBoot implicitly handles it. (I have heard this. Please correct if I am wrong.)
I think that the error comes up because of a missing value in the request. What Spring is saying by handleMissingValue? What am I missing?
you need to specify that your controller is expecting multipart
#RequestMapping(method = RequestMethod.POST, value = "/tender/save-new/save-photo", consumes = {"multipart/form-data"})
public ResponseEntity<?> uploadPhoto(#RequestParam("file") MultipartFile file){
Also to solve the CORS problem you need to add the methods you are planning to use in your cors mapping, try something like this
#Configuration
public class WebMvcConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD");
}
};
}
}
i had the same problem, this is the solution i am using right now:
for the back end using spring boot:
#RequestMapping(value="/save", method = RequestMethod.POST)
public ResponseEntity<?> saveTemp(#RequestParam("file") MultipartFile file) throws Exception{
String nomFichier=file.getOriginalFilename();
try {
byte[] bytes = file.getBytes();
File fi=new File(tempRepo+nomFichier);
fi.getParentFile().mkdirs();
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream((new FileOutputStream(fi)));
bufferedOutputStream.write(bytes);
bufferedOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(HttpStatus.OK);
}
for the front end using Angular2:
public save(file:any){
const formData = new FormData();
formData.append("file", file);
return this._http
.post('http://localhost:8081/save', formData)
.catch(this._errorhandler);
}

How to pass a MultipartHttpServletRequest?

Before posting this, I searched on stack overflow and did the applicable answer. I tried putting enctype on my form tag,
<form name="something" method="post" enctype="multipart/form-data">
adding MultipartResolver on my bean,
<bean id="spring.RegularCommonsMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
but none of these solved my problem.
I want a method that accepts MultipartHttpServletRequest as the parameter. But the browser console gives me this error:
POST link.json 500 Internal Server Error
Eclipse on the other hand throws this error:
Servlet.service() for servlet [action] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: Current request is not of type [org.springframework.web.multipart.MultipartHttpServletRequest]
My controller code looks like this:
#RequestMapping("myjson/myLink")
public void myMethod(MultipartHttpServletRequest request)
{
}
My code accepts HttpServletRequest and not MultipartHttpServletRequest. Is there other way to this?
I badly need MultipartHttpServletRequest because of its getFile method. I need to get an image from the client and store it on the server.
This will surely work for you.
HTML:
<form action="myjson/myLink" id="fileForm" method="POST" enctype="multipart/form-data">
<input type="file" name="File"/>
</form>
Controller:
#RequestMapping(value = "/myjson/myLink", method = RequestMethod.POST)
public #ResponseBody String SaveFile(HttpServletRequest request, #RequestParam("File") MultipartFile file) {
if(!file.isEmpty())
{
try
{
File convFile = new File(//here file location+filename);
convFile.createNewFile();
FileOutputStream fos = new FileOutputStream(convFile);
fos.write( file.getBytes() );
fos.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Spring Configuration:
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>
and in your Spring Initializer class Define MultipartConfigElement element
public class SpringInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SpringConfiguration.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setMultipartConfig(getMultipartConfigElement());
}
private MultipartConfigElement getMultipartConfigElement() {
MultipartConfigElement multipartConfigElement = new MultipartConfigElement( LOCATION, MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD);
return multipartConfigElement;
}
private static final String LOCATION = System.getenv("TEMP").replace('\\', '/') + "/"; // Temporary location where files will be stored
private static final long MAX_FILE_SIZE = 5242880; // 5MB : Max file size.
// Beyond that size spring will throw exception.
private static final long MAX_REQUEST_SIZE = 20971520; // 20MB : Total request size containing Multi part.
private static final int FILE_SIZE_THRESHOLD = 0; // Size threshold after which files will be written to disk
}

Throw exception from spring controller which producces xml MediaType

I have the the following controller with one RequestMapping which produces an xml MediaType.
#RestController
#RequestMapping("/api")
public class ArticleResource {
#RequestMapping(value = "/xml/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<byte[]> getXml(#PathVariable(value = "id") String id,
final HttpServletRequest request,
final HttpServletResponse response) {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(path + id + ".xml");
} catch (FileNotFoundException e) {
throw new BadRequestException("No such xml exists");
}
try {
return new ResponseEntity<byte[]>(IOUtils.toByteArray(inputStream), HttpStatus.OK);
} catch (IOException e) {
e.printStackTrace();
}
return new ResponseEntity<byte[]>(HttpStatus.NOT_FOUND);
}
}
The BadRequestException implementation is the following:
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
public class BadRequestException extends RuntimeException {
public BadRequestException(String message) {
super(message);
}
}
It works fine when the xml exists, but when the xml cannot be found I have a 406 error code. I suppose the problem occurs because it expects a xml media type and instead a RuntimeException is returned. How can I tackle with this issue?
Do you have an Accept: header in your HTTP request? Your error handler will just return an HTTP error code (response status) so it causes a 406 Not Acceptable on the client side if the client expects XML.
If this is the case you can return an XML response entity from the error handler and update your signature to reflect that it produces XML. Or you can try removing the Accepts from your request.
I solved my issue by returning the following:
String returnString = "XML file don't exists";
return new ResponseEntity<byte[]>(IOUtils.toByteArray(
new ByteArrayInputStream(returnString.getBytes())), HttpStatus.NOT_FOUND);

Paypal IPN verification failed because character encoding

I have a problem with Paypal IPN verification in my Spring boot server. I'm not sure where is the problem, if at the server's side or in the other hand, it's Paypal's fault. I already selected UTF-8 as enconding in my profile page.
The main problem it's IPN with UTF-8 characters, which are making the verification fail I guess.
If I have no CharacterEncodingFilter in my Spring and Spring security server, IPN verification works fine. BUT makes other things (forms, for example) not showing with UTF-8 encoding, so this is an unacceptable solution.
I find strange when I'm printing the IPN (with no CharacterEnconding, so payment gets Verified) the response I get (among other things):
charset=UTF-8
address_name=Adrián
payment_status=Completed
So Paypal says that IPN it's UTF-8 but that's what I'm not receiving.
The server's encoding it's working fine adding CharacterEncodingFilter before Spring Security filter chain:
#Order(1)
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
#Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
FilterRegistration.Dynamic characterEncodingFilter = servletContext
.addFilter("characterEncodingFilter", new CharacterEncodingFilter());
characterEncodingFilter.setInitParameter("encoding", "UTF-8");
characterEncodingFilter.setInitParameter("forceEncoding", "false");
characterEncodingFilter.addMappingForUrlPatterns(null, false, "/*");
insertFilters(servletContext, new MultipartFilter());
}
}
And now, Paypal's IPN printing show params well encoded:
charset=UTF-8
first_name=Adrián
payment_status=Completed
but Paypal's response is INVALID.
This is my Controller that handles Paypal IPN's post:
#RequestMapping(value = "paypalok", method = RequestMethod.POST)
public void processIPN(HttpServletRequest request) {
String PAY_PAL_DEBUG = "https://www.sandbox.paypal.com/cgi-bin/webscr";
String CONTENT_TYPE = "Content-Type";
String MIME_APP_URLENC = "application/x-www-form-urlencoded";
String PARAM_NAME_CMD = "cmd";
String PARAM_VAL_CMD = "_notify-validate";
String PAYMENT_COMPLETED = "Completed";
String paymentStatus = "";
// Create client for Http communication
HttpClient httpClient = HttpClientBuilder.create().build();
// Request configuration can be overridden at the request level.
// They will take precedence over the one set at the client level.
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(40000).setConnectTimeout(40000)
.setConnectionRequestTimeout(40000).build();
HttpPost httppost = new HttpPost(PAY_PAL_DEBUG);
httppost.setHeader(CONTENT_TYPE, MIME_APP_URLENC);
try {
Map<String, String> params = new HashMap<String, String>();
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair(PARAM_NAME_CMD, PARAM_VAL_CMD));
// Process the parameters
Enumeration<String> names = request.getParameterNames();
while (names.hasMoreElements()) {
// String param = names.nextElement();
// String value = request.getParameter(param);
String param = new String (names.nextElement().getBytes ("iso-8859-1"), "UTF-8");
String value = new String (request.getParameter(param).getBytes ("iso-8859-1"), "UTF-8");
nameValuePairs.add(new BasicNameValuePair(param, value));
params.put(param, value);
System.out.println(param + "=" + value);
// Get the payment status
if (param.equalsIgnoreCase("payment_status")) paymentStatus = value;
}
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
if (verifyResponse(httpClient.execute(httppost))) {
// if (paymentStatus.equalsIgnoreCase(PAYMENT_COMPLETED)) do...
return "elovendo/pricing/paymentOk";
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return "redirect:/error";
} catch (ClientProtocolException e) {
e.printStackTrace();
return "redirect:/error";
} catch (IOException e) {
e.printStackTrace();
return "redirect:/error";
}
}
private boolean verifyResponse(HttpResponse response) throws IllegalStateException, IOException {
String RESP_VERIFIED = "VERIFIED";
InputStream is = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String responseText = reader.readLine();
is.close();
System.out.println("RESPONSE : " + responseText);
return responseText.equals(RESP_VERIFIED);
}
I have uri encoding with:
#Configuration
public class WebAppConfiguration {
/** HTTPS and Paging error **/
#Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.setUriEncoding("UTF-8");
}
}
Resuming, if I send the characters UTF-8 encoded Paypal verification fails, even when it shouldn't come bad-encoded. If I send them bad-encoded, Paypal's response it's ok.
I can't send the IPN's response bad-encoded using CharacterEncodingFilter, can't I?
I'm don't really know what's going on.
Thank you!
Well, I actually don't know why Paypal is sending data wrong encoded, but a simply workaround manages that.
Just overriding CharacterEncodingFilter like this:
public class CharacterEncodingFilter extends org.springframework.web.filter.CharacterEncodingFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request != null && !request.getRequestURI().contains("paypalcheck")) {
super.doFilterInternal(request, response, filterChain);
}
else {
filterChain.doFilter(request, response);
}
}
}
making reference to the controller URL that listens the Paypal's IPN and telling the Filter that don't encode the data.
And also, making sure that the filter is before Spring Security chain:
public class SecurityConf extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
http.addFilterBefore(filter, WebAsyncManagerIntegrationFilter.class);
}
}

Resources