Spring Controller sending image to client results in 406 - spring

I'm trying to send an image to the front end upon request, it works if i put it in the request body as part JSON, but i want to use image/png, makes more sense, but i get a 406 when i try that.
Controller:
#RequestMapping(value = RESTPaths.EQUIPMENT_FILE_GET_IMAGE + "/{equipmentId}", method = RequestMethod.GET,
produces = MediaType.IMAGE_PNG_VALUE)
public #ResponseBody byte[] insertDataFile(#PathVariable("equipmentId") final Long equipmentId)
throws InternalServerError {
return equipmentFileService.getImage(equipmentId);
}
Test (client):
mockMvc.perform(
get(RESTPaths.EQUIPMENT_FILE_CONTROLLER + RESTPaths.EQUIPMENT_FILE_GET_IMAGE + "/" + equipment.getId())
.with(httpBasic("user", "password")).accept(MediaType.IMAGE_PNG)
.contentType(TestUtil.APPLICATION_JSON_UTF8)).andDo(MockMvcResultHandlers.print()).andExpect(status().isOk());
}
What am i missing?

Try adding the mvc annotation in servlet-context.xml file which registers a ByteArrayHttpMessageConverter
<mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>image/jpeg</value> <value>image/png</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>

Solved:
#RequestMapping(value = RESTPaths.EQUIPMENT_FILE_GET_IMAGE + "/{equipmentId}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<byte[]> getImage(#PathVariable("equipmentId") final Long equipmentId)
throws InternalServerError {
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
return new ResponseEntity<byte[]>(equipmentFileService.getImage(equipmentId), headers, HttpStatus.OK);
}

Related

AJAX get returns 404 in Spring

help me
index.jsp
$("#btn-submit").click(function () {
var username=document.getElementById("username");
var password=document.getElementById("password");
$.ajax({
url:"login",
contentType: 'application/json;charset=utf-8',
dataType: 'text',
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
data: {
username:username.value,
password:password.value
},
type: 'get',
success: function (response) {
if (response=="1") {
alert(response);
}
else alert(response);
},
error: function (x, e) {
console.log(e)
}
});
});
LoginController.java
#RequestMapping("/login")
#Controller
public class LoginController {
#Autowired
private UserService userService;
#RequestMapping(value = { "/login" }, method = RequestMethod.GET)
#ResponseBody
public int checkValid(#RequestParam("username") String username,#RequestParam("password") String password, HttpServletRequest request, HttpServletResponse response, Locale locale, Model model){
try {
if (userService.findByUserName(username).equals(hashPass(password))){
return 1;
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return 0;
}
return 0;
}
public String hashPass(String pass) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hashInBytes = md.digest(pass.getBytes(StandardCharsets.UTF_8));
// bytes to hex
StringBuilder sb = new StringBuilder();
for (byte b : hashInBytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}
spring-config-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
/WEB-INF/pages/
.jsp
/resources/jdbc.properties
<!-- Enable Annotation based Declarative Transaction Management -->
<tx:annotation-driven proxy-target-class="true"
transaction-manager="transactionManager" />
<!-- Creating TransactionManager Bean, since JDBC we are creating of type
DataSourceTransactionManager -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="postsDAO" class="com.blog.dao.impl.PostsDAO">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="postsService" class="com.blog.service.impl.PostsService">
<property name="postsDAO" ref="postsDAO"/>
</bean>
<bean id="userDAO" class="com.blog.dao.impl.UserDAO">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="userService" class="com.blog.service.impl.UserService">
<property name="userDAO" ref="userDAO"/>
</bean>
I use tomcat 9
Error:Failed to load resource: the server responded http://localhost:8080/Blog_war_exploded/login?username=root&password=root with a status of 404 ()
Look at your error: You are accessing http://localhost:8080/Blog_war_exploded/login but you actually want to access http://localhost:8080/login.
The reason is that you specified your URL as login instead of /login, so it is relative to the current "directory" and not to the root.
Changing the code to use /login should fix it:
$.ajax({
url: "/login",
...
})
On a side note, it's not a good idea to this via GET requests - among other things, the password will be stored in the server log in clear text. You should use a POST request instead.
Update:
Also, it seems you are use two request mappings for /login on top of each other, so you'll end up with /login/login. Check out how to use #RequestMapping properly.
Try changing the second (method-level) one to #RequestMapping(value = { "/" }, method = RequestMethod.GET) or just #RequestMapping("/").
I think the issue is related to your RequestMapping definition on both controller level and method level.
the first login at the controller level, means if you want to access any services in this controller, your requests have to start with "/login"
#RequestMapping("/login")
#Controller
public class LoginController {
and the second login at the method level, means you want to call the /login service under /login.
#RequestMapping(value = { "/login" }, method = RequestMethod.GET)
#ResponseBody
public int checkValid(#RequestParam("username") String username,#RequestParam("password") String password, HttpServletRequest request, HttpServletResponse response, Locale locale, Model model){
So the valid URL to call the /login service under /login controller is: /login/login
and because of this, your url /login was not found
you can either remove the first /login at the controller level, or use the /login/login from your ajax request...

Spring Boot Produces text/csv, Could not find acceptable representation

I am trying to get my Spring Boot application to return accept=text/csv, I continue to get:
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not
find acceptable representation
I've added:
compile "com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson_version}"
compile "com.fasterxml.jackson.dataformat:jackson-dataformat-csv:${jackson_version}"
To my build.gradle, I am NOT using SpringMVC
and the handler looks like:
#RequestMapping(value = "/{id}/csv", method = RequestMethod.GET, produces = "text/csv")
public List<RegistrationCode> exportToCsv(#ApiParam(name = "id", required = true, value = "string") #PathVariable String id, HttpServletResponse response) {
...
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"",
csvFileName);
response.setHeader(headerKey, headerValue);
response.setContentType("text/csv;charset=utf-8");
return registrationCodes;
}
Curl example:
curl -X GET --header 'Accept: text/csv' --header 'Authorization: Bearer ...' 'http://localhost:8080/api/1001/csv'
Message Converter:
public class CsvMessageConverter extends AbstractHttpMessageConverter<List<RegistrationCode>> {
}
Example adding message converts (in traditional applicationContext.xml):
<util:list id="messageConverters">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"
p:objectMapper-ref="jsonObjectMapperFactory"/>
<!--bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter"
p:objectMapper-ref="xmlObjectMapperFactory"/-->
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="com.binding.CsvMessageConverter"/>
</util:list>
//Adding the message converter
#Configuration
public class MyApplicationConfiguration {
...
#Bean
public HttpMessageConverters customConverters() {
return new HttpMessageConverters(new CsvMessageConverter());
}
}
I was able to find some instructions for registering a convert here:
In Spring Boot, adding a custom converter by extending MappingJackson2HttpMessageConverter seems to overwrite the existing converter

Getting error to unmarshalling object from xml using resttemplate

I am using resttemplate of spring to invoke rest api getting error to unmarshall xml to object my code is:-
String uri = "http://devd.webservice.com/devpl/api/1.0/credential?apiKey=" + apiKey + "&signature=" + signature + "&timeStamp=" + timeStamp;
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("accountName", accountName);
requestHeaders.set("containerName", containerName);
requestHeaders.set("folderPath", folderPath);
requestHeaders.set("Content-Type","application/xml");
requestHeaders.set("Accept","application/xml");
RestTemplate template = getRestTemplate();
HttpEntity<String> requestEntity = new HttpEntity<String>(requestHeaders);
Credential result =(Credential)template.postForObject(uri,requestEntity,Credential.class);
Object classs bean on which i consume object:-
package com.simplidrivechn.netmagicsolutions.bean;
import com.thoughtworks.xstream.annotations.*;
#XStreamAlias("credential")
public class Credential
{
private String DestinationUrl;
private String AuthToken;
private String StorageUrl;
public String getAuthToken() {
return AuthToken;
}
public void setAuthToken(String AuthToken) {
this.AuthToken = AuthToken;
}
public String getDestinationUrl() {
return DestinationUrl;
}
public void setDestinationUrl(String DestinationUrl) {
this.DestinationUrl = DestinationUrl;
}
public String getStorageUrl() {
return StorageUrl;
}
public void setStorageUrl(String StorageUrl) {
this.StorageUrl = StorageUrl;
}
}
My spring configuration file:-
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean id="messageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="xstreamMarshaller" />
<property name="unmarshaller" ref="xstreamMarshaller" />
</bean>
</list>
</property>
</bean>
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<props>
<prop key="credential">com.simplidrivechn.netmagicsolutions.bean.Credential</prop>
</props>
</property>
</bean>
</beans>
I am getting error:-
Exception in thread "main" org.springframework.http.converter.HttpMessageNotReadableException: Could not read [class com.simplidrivechn.netmagicsolutions.bean.Credential]; nested exception is org.springframework.oxm.UnmarshallingFailureException: XStream unmarshalling exception; nested exception is com.thoughtworks.xstream.mapper.CannotResolveClassException: Credential : Credential
please help me to resolve this error
Looking at your exception, it looks like that XStreamMarshaller's aliases are not set correctly in your spring context. You must make sure that your keys are 'aliases', i.e. root element in your case. Is 'credential' the root element of the xml response you are trying to deserialize? Note that aliases are case sensitive. Following code works for me. Note aliases.put("person", Person.class);My xml response has root element 'person'. If I change this key to lets say 'Person' like aliases.put("Person", Person.class); I exactly get the exception like you.
XStreamMarshaller marshaller = new XStreamMarshaller();
Map<String, Class> aliases = new HashMap<String, Class>();
aliases.put("person", Person.class);
marshaller.setAliases(aliases);
MarshallingHttpMessageConverter converter = new MarshallingHttpMessageConverter(
marshaller, marshaller);
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(converter);
template.setMessageConverters(converters);
HttpEntity request = new HttpEntity(null, headers);
ResponseEntity<Person> response = template.exchange(url,
HttpMethod.GET, request, Person.class);
Another way to define aliases is autoscan.
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="autodetectAnnotations" value="true"/>
<property name="annotatedClasses">
<array>
<value>com.simplidrivechn.netmagicsolutions.bean.Credential</value>
</array>
</property>
</bean>

Apache HttpClient making multipart POST to Spring #Controller class

It seems like there are several posts such as here asking how to use Apache Commons HTTPClient libraries in Java to do a POST to a Servlet. However, it seems like I'm having some problems doing the same thing with a annotated Spring controller method. I've tried a few things but gotten HTTP 401 Bad Request responses from the server. Any examples of doing this would be greatly appreciated.
EDIT: Code I am trying to use:
//Server Side (Java)
#RequestMapping(value = "/create", method = RequestMethod.POST)
public void createDocument(#RequestParam("userId") String userId,
#RequestParam("file") MultipartFile file, HttpServletResponse response) {
// Do some stuff
}
//Client Side (Groovy)
void processJob(InputStream stream, String remoteAddress) {
HttpClient httpclient = new DefaultHttpClient()
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1)
HttpPost httppost = new HttpPost("http://someurl/rest/create")
MultipartEntity mpEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE)
InputStreamBody uploadFilePart = new InputStreamBody(stream, 'application/octet-stream', 'test.file')
mpEntity.addPart('file', uploadFilePart)
mpEntity.addPart('userId', new StringBody('testUser'))
httppost.setEntity(mpEntity)
HttpResponse response = httpclient.execute(httppost);
println(response.statusLine)
}
Still getting 400 Bad Request in the response from the server.
I hate to answer my own question when it shows incompetence, but it turns out the code was fine, this particular controller did not have a CommonsMultipartResolver defined in its servlet-context.xml file (multiple DispatcherServlets...long story :()
Here's what I added to make it work:
<!-- ========================= Resolver DEFINITIONS ========================= -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="50000000"/>
</bean>
Here is an example from the Spring Reference:
#Controller
public class FileUpoadController {
#RequestMapping(value = "/form", method = RequestMethod.POST)
public String handleFormUpload(#RequestParam("name") String name,
#RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
byte[] bytes = file.getBytes();
// store the bytes somewhere
return "redirect:uploadSuccess";
} else {
return "redirect:uploadFailure";
}
}
}

spring restTemplate POST parameters from complex object

I'm attempting to test our REST service using restTemplate using the postForObject(...) method.
unit test:
#Test
public void testPostOrder() {
String url = BASE_URL + "/orders/";
OrderDto orderDtoInput = new OrderDto();
orderDtoInput.setCustomerId(34);
UpdateReportDto updateReport = restTemplate.postForObject(url,
orderDtoInput, UpdateReportDto.class, new Object[] {});
}
the interesting piece of my configuration:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<ref bean="formHttpMessageConverter" />
<ref bean="marshallingHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="formHttpMessageConverter" class="org.springframework.http.converter.FormHttpMessageConverter">
</bean>
I understand that the FormHttpMessageConverter will convert to and from MultiValueMap and media type
application/x-www-form-urlencoded.
Is there any magic, or tools I can use or wire in to convert my Dto to a MultiValueMap ??? or do I need to cycle over the object properties and build my own MultiValueMap in my test?
my server is expecting to get POST parameters that look something like this:
id=11752&firstName=Joe&active=true&address1=1122&address2=2233&c
ellPhone=123-321-1234&childrensName1=bobby1&childrensName2=bobby2&childrensName3=bobby3&childrensName4=bobby4&city=someCity&
customHobbies=loves To Fly Planes&distributorId=407&email=doc#surgeon.com&fax=321-123-1234&fellowship=good fellows&fishing=false&golf=true&hunting=false&
insuranceCompany1=ins1&insuranceCompany2=ins2&insuranceCompany3=ins3&insuranceCompany4=ins4&lastName=Brownie&
mailMerge=true&medicalSchool=Granada U&officeDays=4&officeManager=manager&officeManagerPhone=456.654.4567&other=true&
paNurse=nurse 1&paNursePhone=345-543-3456&
phone=234-432-2345&
salesRepresentativeId=1935&specialty=meatball surgery&spouseName=Betty&state=AL&
surgeryDays=22&title=doc&version=2&zip=47474
promptValues[0].id=12&promptValues[0].miscPromptId=882&promptValues[0].value=meFirst&
promptValues[1].id=13&promptValues[1].miscPromptId=881&promptValues[1].value=youToo&residency=Jamaica General&
surgeonClinics[0].address1=newAddress&surgeonClinics[0].address2=newAddress2&surgeonClinics[0].city=clinic City&
surgeonClinics[0].email=email#clinic1.com&surgeonClinics[0].fax=123.456.7890&surgeonClinics[0].id=33273&
surgeonClinics[0].name=clinic name&surgeonClinics[0].phone=890-098-4567&
surgeonClinics[0].zip=34567&surgeonClinics[0].surgeryCenter1=MySurgeryCenter1&
surgeonClinics[0].surgeryCenter2=MySurgeryCenter2&
surgeonClinics[1].address1=newAddress11&surgeonClinics[1].address2=newAddress22&surgeonClinics[1].city=clinic2 City&
surgeonClinics[1].email=email#clinic2.com&surgeonClinics[1].fax=123.456.7890&surgeonClinics[1].id=33274&
surgeonClinics[1].name=clinic2 name&surgeonClinics[1].phone=890-098-4567&
surgeonClinics[1].zip=34567&
surgeonClinics[1].surgeryCenter1=MySurgeryCenter21&surgeonClinics[1].surgeryCenter2=MySurgeryCenter22&
Here's what I don't get: our RestServiceController method knows how to take this crazy parameter list and re-create our Dto object. We can successfully call it using curl. It seems that some reciprocal magic should exist on the client side to turn the Dto into the parameter list.
Here's the signature of the server side controller method:
// createOrder
#RequestMapping(method = { RequestMethod.POST, RequestMethod.PUT }, value = "/orders/")
#ResponseBody
public UpdateReportDto createOrder(OrderDto orderDto,
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) {
You can use RestTemplate with message converters. I have tested it and it works
RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new MappingJackson2HttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
restTemplate.postForEntity(url, requestBodyObject, returnTypeClass);

Resources