In my controller I have the following method:
import net.glxn.qrgen.QRCode;
import org.marcio.demospringboot.dao.FormationRepository;
import org.marcio.demospringboot.model.Formation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayOutputStream;
import java.util.Map;
#Controller
public class FormationController {
#Autowired
private FormationRepository formationRepository;
#RequestMapping (value="formation/qr/{id}", method = RequestMethod.GET)
public ResponseEntity<byte[]> qr(#PathVariable final Long id) {
ByteArrayOutputStream stream = QRCode.from(formationRepository.findOne(id).toString()).stream();
byte[] bytes = stream.toByteArray();
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<byte[]> (bytes, headers, HttpStatus.CREATED);
}
}
In my html page:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>QR Code</title>
</head>
<body>
<img th:src="#{/formation/qr/${id}}" />
</body>
</html>
This is the generated image:
I want to get user data from your "id". I am using a simple repository Spring formationRepository and the library net.glxn.qrgen.QRCode.The application works, but not generate the QR code with the user data regarding the "id". Thanks.
Forgot '/' #RequestMapping (value="/formation/qr/{id}", method = RequestMethod.GET) before formation
EDIT:
ByteArrayOutputStream stream = QRCode.from(formationRepository.findOne(id).toString()).stream();
byte[] data = stream.toByteArray();;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
headers.setContentLength(data.length);
return new HttpEntity<byte[]>(data, headers);
This should work in order so the browser will understand it is an image and will show it
Thank you for your help and comments. They were all very helpful. I could solve the problem by upgrading to:
#RequestMapping (value="/formation/qr/{id}", method = RequestMethod.GET)
public HttpEntity<byte[]> qr(#PathVariable Long id) {
byte[] bytes = QRCode.from(formationRepository.findOne(id).getTheme()
.toString()).withSize(120, 120).stream().toByteArray();
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
headers.setContentLength(bytes.length);
return new ResponseEntity<byte[]> (bytes, headers, HttpStatus.CREATED);
}
The solution was byte []bytes = QRCode.from(formation Repository.findOne (id).getTheme(). So I got the registration content (getTheme) and presents it in QR code.
Related
I am working on creating an app using springboot which would consume an API which has OAuth2 authentication. Post successful getting the Bearer code I would be calling another API which would actually give me data for further processing. I have custom OAuth url, authorization code, username, password, secret key, api key. When I searched on internet, none of the example were usign all of these[only secret key, authorization code and api key was getting used.]. Do I need to use username and password as well?
I tried below code [and few other things]. But not able to get through this.
<code>
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.xml.bind.DatatypeConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.support.BasicAuthorizationInterceptor;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
#Slf4j
#Component
public class ApiConsumer {
#Autowired
private RestTemplate template;
#Value("${oauth.api}")
String url;
#Value("${oauth.oAuth.url}")
String oAuthUrl;
#Value("${oauth.user}")
String username;
#Value("${oauth.password}")
String password;
#Value("${oauth.apikey}")
String apiKey;
#Value("${oauth.secretkey}")
String apiSecret;
public String postData() {
log.info("Call API");
try {
String response = consumeApi();
if (response.equals("200")) {
log.info("posting data to another api");
// CALL another API HERE for actual data with bearer code
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
private String consumeApi() throws Exception {
String authorizationHeader = "Basic "
+ DatatypeConverter.printBase64Binary((apiKey + ":" + apiSecret).getBytes());
// setting up the HTTP Basic Authentication header value
HttpHeaders requestHeaders = new HttpHeaders();
// set up HTTP Basic Authentication Header
requestHeaders.add("Authorization", authorizationHeader);
requestHeaders.add("Accept", MediaType.APPLICATION_FORM_URLENCODED_VALUE);
requestHeaders.add("response_type", "code");
// request entity is created with request headers
HttpEntity<String> request = new HttpEntity<String>(requestHeaders);
template.getInterceptors().add(new BasicAuthorizationInterceptor(username, password));
ResponseEntity<String> result = null;
try {
result = template.exchange(oAuthUrl, HttpMethod.POST, request, String.class);
log.info( result.getBody());
if (result.getStatusCode() == HttpStatus.OK) {
transformData(result.getBody());
}
if (result.getStatusCode() != HttpStatus.REQUEST_TIMEOUT) {
throw new Exception("Api taking too long to respond! ");
}
}
catch (Exception e) {
log.error("Api taking too long to respond!");
}
return "";
}
private void transformData(String body) throws JsonMappingException, JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
List<HeapEntity> heapEntityList = Arrays.asList(mapper.readValue(body, HeapEntity[].class));
if (heapEntityList != null && heapEntityList.size() > 0) {
heapEntityList.forEach(i -> i.getPhoneNumber().replaceAll("-", ""));
}
log.debug("Size of list is :: " + heapEntityList.size());
heapEntityList.add(null);
}
}
</code>
Unfortunately, I cannot give a direct answer to your question, because it is not clear from it which grant type you are trying to use, and this will determine the answer to the question whether you need to use a username and password or not.
I advise you to familiarize yourself with the Section 4 of RFC 6749, in which you will find information on all grant types supported by the standard, and the request parameters they require.
Examples for the Password grant type:
If you need to use the RestTemplate, you can do something like this:
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/x-www-form-urlencoded");
headers.set("Authorization", "Basic " + Base64.getUrlEncoder().encodeToString((clientId + ":" + clientSecret).getBytes()));
String body = String.format("grant_type=password&username=%s&password=%s", username, password);
String json = restTemplate.postForObject(tokenUrl, new HttpEntity<>(body, headers), String.class);
Note that the response is a json object containing a token, not the token itself.
Or you can simply use the more appropriate for your purpose OAuth2RestTemplate:
#Bean
public OAuth2RestTemplate oAuth2RestTemplate() {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
resource.setClientAuthenticationScheme(AuthenticationScheme.form);
resource.setAccessTokenUri("tokenUrl");
resource.setClientId("clientId");
resource.setClientSecret("clientSecret");
resource.setUsername("username");
resource.setPassword("password");
return new OAuth2RestTemplate(resource);
}
Do not forget to add #EnableOAuth2Client to one of your configuration classes.
I'm creating a web application for which I'm using Vue for the frontend and Spring Boot for the backend. Spring Boot serves index.html at / and /index.html, but I want it to be served at other URL's too, for example /account, which in turn will be detected by Vue's Router and will show the proper page.
Additionally, I have some other URL's I don't want to serve index.html. All of them start with /api, meaning that's the place where the Vue app sends requests.
Any help will be appreciated. Thanks.
What you want to do is called an SPA (single page application). In order to achive this you need to do two things:
Tell vue-router to use HTML5 history push: https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations
Tell SpringBoot to serve the index.html when it cannot find a relevant route. Here is a good guide on how to do it using a handler for NoHandlerFoundException: https://medium.com/#kshep92/single-page-applications-with-spring-boot-b64d8d37015d
I have to warn you: when you configure history mode in step 1., click something, it will look like your SPA is already working (no # sign). Beware that this is an illusion. Vue-router tells the browser how the url should look like, but when you refresh the page, the server will return 404. You have to configure step 2 as well.
Because in my application I do not have only VUE in the user interface, redirect all errors to the VUE index.html as is proposed before is not acceptable in my scenario.
Finally, I have solved in another manner using filters ( basically the idea is to intercept all URL that are not css, js, images, etc... used in my VUE UI and take control of the response). In my case the VUE URL starts with "/context/kmobile/":
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
#Component
public class Html5PathFilter extends OncePerRequestFilter {
private static final Logger log = LoggerFactory.getLogger(Html5PathFilter.class);
// Capture the content of a file from /webapps/kmobile/index.html
// Inspired by https://stackoverflow.com/questions/30431025/spring-how-to-access-contents-of-webapp-resources-in-service-layer
#Value("/kmobile/index.html")
private Resource indexResource;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
String path = request.getServletPath();
if (!path.endsWith(".css") && !path.endsWith(".js") && !path.endsWith(".ico") && !path.endsWith(".html") &&
!path.endsWith("/kmobile/")) {
// log.info("YES, do redirect ->" + path);
// Code warning, initially were using redirect, that's a bad practice because from browser get the index.html url what never should be used directly there
// response.sendRedirect(request.getContextPath() + "/kmobile/index.html");
// Disable browser cache
response.setHeader("Expires", "Sat, 6 May 1971 12:00:00 GMT");
response.setHeader("Cache-Control", "must-revalidate");
response.addHeader("Cache-Control", "no-store, no-cache, must-revalidate");
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
response.addHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Pragma", "no-cache");
InputStream is = indexResource.getInputStream();
// Set MIME type
response.setContentType("text/html");
// Content leght
response.setContentLength(is.available());
try (ServletOutputStream out = response.getOutputStream()) {
IOUtils.copy(is, out);
out.flush();
}
return;
} else {
// log.info("NO, do redirect ->" + path);
}
} catch (Exception e) {
log.debug("Error: {}", e.getMessage(), e);
}
//log.info("--> {}", request.getServletPath());
filterChain.doFilter(request, response);
}
#Override
protected boolean shouldNotFilter(HttpServletRequest request) {
String path = request.getServletPath();
boolean valid = path.startsWith("/kmobile");
if (valid) {
log.info("path: {} => {}", path, valid);
}
return !valid;
}
}
Servlet:
package world.hello;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import world.hello.MyMainClass;
public class TestServlet extends HttpServlet{
private static final int BYTES_DOWNLOAD = 1024;
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws IOException
{
response.setContentType("text/plain");
OutputStream os = response.getOutputStream();
os.write(("hello world"+Double.toString(Math.random())).getBytes());
os.flush();
os.close();
}
public void doPost(HttpServletRequest request,
HttpServletResponse response) throws IOException
{
doGet(request, response);
}
}
HTML:
<html>
<body>
<script>
function myAjax()
{
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("GET","RunQuery", false);
xmlhttp.send();
document.getElementById("myText").innerHTML=xmlhttp.responseText + " " + xmlhttp.readyState.toString() + " " + xmlhttp.status.toString() ;
document.getElementById("myText2").innerHTML=Math.random();
}
</script>
<button id = "myButton" onclick = "myAjax()">click me</button>
<div id = "myText"></div>
<div id = "myText2"></div>
</body>
</html>
If I access the servlet directly at http://localhost:9070/test_web_project_1/RunQuery
Each time I refresh it, I get a different random float displayed.
When I run the HTML at http://localhost:9070/test_web_project_1/myxjax.html, The second float changes, the first is fixed.
What is causing this, and how do i resolve it?
Nevermind what I said before...your code is synchronous because you set async to false. Your issue is just browser caching. Your ajax request is being cached. You can trick the browser to not load the cache by adding a parameter with the date/time to the request like:
var d = new Date();
xmlhttp.open("GET","RunQuery?ts="+d.getTime(), false);
That just makes the browser see each request as unique; there's no need to do anything with that param on the server side.
Or, you could add no-cache headers in the servlet being called by the Ajax. You can also do both to be extra cautious.
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma","no-cache"); //HTTP 1.0
response.setDateHeader ("Expires", 0);
I am using Spring MVC 3.4.0. When i tried CRUD example I get this error in my browser console;
HTTP Status 400 - The request sent by the client was syntactically
incorrect.
My codes:
EditBlog.jsp;
<%#taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%# page contentType="text/html; charset=UTF-8" language="java"%>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%# taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"%>
<form action="/testhibernate/edit/${blogID}/" method="POST" name="BLOG">
<h3>TITLE</h3>
<input name="TITLE" type="text" value="${blogList.title}" size="30"/>
<h3>CREATE_DATE</h3>
<input name="CREATE_DATE" type="date" value="${blogList.createDate}" size="30"/>
<h3>TEXT_CONTENT</h3>
<input name="TEXT_CONTENT" type="text" value="${blogList.textContent}" size="30"/>
<br>
<input name="action" type="submit" value="Edit" size="30"/>
</form>
editController ;
package com.basari.testhibernate;
import java.util.Date;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import com.basari.blog.Blog;
import com.basari.blog.User_Blog_App;
#Controller
public class editController {
#Autowired
private User_Blog_App deneme1;
#RequestMapping(value = "/edit/{blogID}", method = RequestMethod.GET)
public ModelAndView findBlog(#PathVariable Integer blogID)
{
ModelAndView mav = new ModelAndView("editBlog");
Blog blog= deneme1.findBlog(blogID);
mav.addObject("blogList", blog);
return mav;
}
#RequestMapping(value = "/edit/{blogID}/", method = RequestMethod.POST)
public ModelAndView editBlog(#PathVariable Integer blogID
, #RequestParam( value = "TITLE", required=false) String title
, #RequestParam( value = "TEXT_CONTENT", required=false) String content
, #RequestParam( value = "CREATE_DATE", required=false) Date date
) {
Blog blog= deneme1.findBlog(blogID);
blog.setTitle( title );
blog.setTextContent( title );
blog.setCreateDate(date);
this.deneme1.editBlog( blog );
ContactController.logger.debug( "contactPost action called ");
try{
}finally{
}
ModelAndView mav = new ModelAndView("editBlog");
mav.addObject("blogList", blog);
return mav;
}
}
edit Function ;
public void editBlog(Blog blog){
Session session =sessionFactory.openSession();
Transaction tx= null;
try{
tx= session.beginTransaction();
session.update(blog);
tx.commit();
}
catch(HibernateException e){
if (tx!=null) tx.rollback();
e.printStackTrace();
}finally{
session.close();
}
}
And there is no error in my JAVA console. What is wrong?
Try this It will work for you
In your controller
#InitBinder
protected void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat,false));
}
The error is almost certainly that Spring cannot convert the date you enter in this <input> field
<input name="CREATE_DATE" type="date" value="${blogList.createDate}" size="30"/>
into an argument to pass to
#RequestParam( value = "CREATE_DATE", required=false) Date date
As a result, the request is a Bad Request and Spring returns you a 400 status code.
Add a #DateTimeFormat annotation to your request parameter. For example,
#RequestParam( value = "CREATE_DATE", required=false) #DateTimeFormat("dd-MM-yyyy") Date date
And then make sure your client sends the appropriate format of date. For example
14-01-2014
What is the best approach to catch an exception in a Spring Web Service, extract the details of it, and format it into a soap response? My error message details must go in the header of the Soap response.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ims="http://www.imsglobal.org/services/lis/cmsv1p0/wsdl11/sync/imscms_v1p">
<soapenv:Header>
<imsx_syncResponseHeaderInfo xmlns="http://www.imsglobal.org/services/lis/cmsv1p0/wsdl11/sync/imscms_v1p0">
<imsx_version>V1.0</imsx_version>
<imsx_messageIdentifier>4</imsx_messageIdentifier>
<imsx_statusInfo>
<imsx_codeMajor>failure</imsx_codeMajor>
<imsx_severity>status</imsx_severity>
<imsx_codeMinor>
<imsx_codeMinorField>
<imsx_codeMinorFieldName>TargetEndSystem</imsx_codeMinorFieldName>
<imsx_codeMinorFieldValue>incompletedata</imsx_codeMinorFieldValue>
</imsx_codeMinorField>
</imsx_codeMinor>
</imsx_statusInfo>
</imsx_syncResponseHeaderInfo>
</soapenv:Header>
<soapenv:Body/>
</soapenv:Envelope>
I do know if it is the best approach but I added a SimpleSoapExceptionResolver object:
import java.util.Date;
import java.util.Locale;
import org.apache.log4j.Logger;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.SoapBody;
import org.springframework.ws.soap.SoapFault;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.server.endpoint.SimpleSoapExceptionResolver;
public final class MySimpleSoapExceptionResolver
extends SimpleSoapExceptionResolver {
public MySimpleSoapExceptionResolver () {
super.setOrder(HIGHEST_PRECEDENCE);
}
#Override
protected void customizeFault( final MessageContext messageContext_,
final Object endpoint_,
final Exception exception_,
SoapFault soapFault_) {
WebServiceMessage _webServiceMessageResponse =
messageContext_.getResponse();
SoapMessage _soapMessage = (SoapMessage) _webServiceMessageResponse;
SoapBody _soapBody = _soapMessage.getSoapBody();
String _message = "your error message";
Logger _logger = Logger.getLogger(MySimpleSoapExceptionResolver.class);
_logger.error(_message, exception_);
soapFault_ =
_soapBody.addServerOrReceiverFault(_message, Locale.ENGLISH);
}
}
You can probably implement a interceptor of type org.springframework.ws.server.endpoint.interceptor.EndpointInterceptorAdapter. Register your interceptor in your webservice configuration.
Implement the method handleResponse(MessageContext messageContext, Object endpoint) like this -
handleResponse(MessageContext messageContext, Object endpoint) {
SoapMessage msg = (SoapMessage) messageContext.getResponse();
SoapHeader header = msg.getSoapHeader();
// do what you want to do with header.
}
I have not implemented this but done similar stuff with interceptors in CXF.