I'm trying to integrate Spring WebFlow (SWF) into an existing Spring Boot + Thymeleaf project but am running into issues when trying to navigate away from my the first template in my flow. Specifically the URL has no flowExecutionKey parameter present, so my link which looks like:
<a th:href="#{${flowExecutionUrl}(_eventId=selectPaymentMethod,type=*{paymentMethod.name})}">
<img th:src="#{|*{paymentMethod.logo}|}" class="img-thumbnail" src="../resources/images/paypal-logo.png" alt="" />
</a>
Ends up translating as a link to:
http://localhost:8080/payments/checkout-widget/session/1/checkout?_eventId=selectPaymentMethod&type=Google+Checkout
From what I've read the flowExecutionUrl should include a flowExecutionKey parameter, something like execution=e3s2. What I instead see with the above URL is that I'm continually redirected back to the first page in my WebFlow. It's almost as if my flow isn't quite wired up correctly although I've spent a good few hours perusing similar issues on Google but can't find anybody having this exact issue. I've checked my JSESSIONID request cookie and this does not change.
Do you know why the flowExecutionUrl is missing or null? If anymore information is needed please just ask :)
Many thanks in advance,
~Ian
WebflowConfig.java:
#Configuration
#AutoConfigureAfter(MvcConfig.class)
public class WebflowConfig extends AbstractFlowConfiguration {
#Autowired
private SpringTemplateEngine templateEngine;
#Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry())
.addFlowExecutionListener(new SecurityFlowExecutionListener())
.build();
}
#Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder(flowBuilderServices())
.addFlowLocation("classpath:/templates/checkout.xml", "checkout")
.build();
}
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setViewFactoryCreator(mvcViewFactoryCreator())
.setDevelopmentMode(true)
.build();
}
#Bean
public FlowController flowController() {
FlowController flowController = new FlowController();
flowController.setFlowExecutor(flowExecutor());
return flowController;
}
#Bean
public FlowHandlerMapping flowHandlerMapping() {
FlowHandlerMapping flowHandlerMapping = new FlowHandlerMapping();
flowHandlerMapping.setFlowRegistry(flowRegistry());
flowHandlerMapping.setOrder(-1);
return flowHandlerMapping;
}
#Bean
public FlowHandlerAdapter flowHandlerAdapter() {
FlowHandlerAdapter flowHandlerAdapter = new FlowHandlerAdapter();
flowHandlerAdapter.setFlowExecutor(flowExecutor());
flowHandlerAdapter.setSaveOutputToFlashScopeOnRedirect(true);
return flowHandlerAdapter;
}
#Bean
public AjaxThymeleafViewResolver thymeleafViewResolver() {
AjaxThymeleafViewResolver viewResolver = new AjaxThymeleafViewResolver();
viewResolver.setViewClass(FlowAjaxThymeleafView.class);
viewResolver.setTemplateEngine(templateEngine);
return viewResolver;
}
#Bean
public MvcViewFactoryCreator mvcViewFactoryCreator() {
List<ViewResolver> viewResolvers = new ArrayList<>();
viewResolvers.add(thymeleafViewResolver());
MvcViewFactoryCreator mvcViewFactoryCreator = new MvcViewFactoryCreator();
mvcViewFactoryCreator.setViewResolvers(viewResolvers);
mvcViewFactoryCreator.setUseSpringBeanBinding(true);
return mvcViewFactoryCreator;
}
}
checkout.xml:
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<on-start>
<set name="flowScope.paymentMethods" value="checkoutService.paymentMethods"/>
</on-start>
<view-state id="payment-methods" view="payment-methods">
<transition on="selectPaymentMethod" to="new-details"/>
</view-state>
<view-state id="new-details" view="new-details">
<transition on="submitDetails" to="summary"/>
</view-state>
<view-state id="summary" view="summary">
<transition on="completeDetails" to="completed"/>
</view-state>
<end-state id="cancelled" view="externalRedirect:contextRelative:/home.do"/>
<end-state id="completed" view="externalRedirect:contextRelative:/home.do"/>
<global-transitions>
<transition on="cancelCheckout" to="cancelled"/>
</global-transitions>
</flow>
WelcomeController.java:
#Controller
#RequestMapping(value = "/payments/checkout-widget/session/{sessionId}")
#SessionAttributes({"paymentMethods", "redirectUrls", "cardDetails"})
public class WelcomeController {
#Inject
private CheckoutWidgetSessionService checkoutWidgetSessionService;
#Inject
private CheckoutService checkoutService;
#RequestMapping(value = "/checkout", method = RequestMethod.GET)
public String intro(
#NotNull #PathVariable("sessionId") String sessionId,
Model model) {
System.out.println("Session ID:" + sessionId);
model.addAttribute("paymentMethods", checkoutService.getPaymentMethods());
model.addAttribute("deliveryAddress", checkoutService.getDeliveryAddress());
model.addAttribute("date",new Date().toString());
return "payment-methods";
}
}
payment-methods.html:
<html>
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="stylesheet"
th:href="#{/css/bootstrap.min.css}"
href="../resources/css/bootstrap.min.css"/>
</head>
<body>
<div class="container">
<h1 th:text="#{payment.methods.title}">Payment Methods</h1>
<br/>
<p th:text="#{payment.methods.label}">Please select a payment method:</p>
<div class="row">
<div class="col-sm-2 col-xs-4 col-md-1 col-lg-1" th:each="paymentMethod : ${paymentMethods}">
<a th:href="#{${flowExecutionUrl}(_eventId=selectPaymentMethod,type=*{paymentMethod.name})}">
<img th:src="#{|*{paymentMethod.logo}|}" class="img-thumbnail" src="../resources/images/paypal-logo.png" alt="" />
</a>
</div>
</div>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
</body>
</html>
EDIT: So it would seem that WebFlow is not compliant with RESTful GET methods (i.e. when you have a dynamic part of the URL which defines the object ID). I have managed to find a work-around for my particular use-case by storing and retrieving the session ID in a different manner than with POST/GET.
Related
My SpringWebConfiguration.class is here:
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
private static Logger logger = LoggerFactory.getLogger(SpringSecurityConfig.class);
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private PasswordEncoder passwordEncoder;
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
logger.info("-----configure(HttpSecurity http)");
http.authorizeRequests()
.antMatchers("/**").permitAll()
.antMatchers("/admin/**").hasAnyRole("ADMIN")
.antMatchers("/user/**").hasAnyRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/login")
.loginPage("/login")//
.defaultSuccessUrl("/userAccountInfo")//
.failureUrl("/login?error=true")//
.usernameParameter("username")//
.passwordParameter("password")
.defaultSuccessUrl("/")
.permitAll().
and().rememberMe().rememberMeParameter("remember-me").key("uniqueAndSecret").tokenValiditySeconds(1296000).userDetailsService(userDetailsService)
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/")
.deleteCookies("guid")
.deleteCookies("JSESSIONID")
.permitAll()
.and().csrf().disable();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
logger.info("-----configureGlobal(AuthenticationManagerBuilder auth)");
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
}
My LoginController:
#RestController
public class LoginController() {
#GetMapping("/login")
public String login(Model model) {
return "/login";
}
}
My html file:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Stacked form</h2>
<form th:action="#{/login}" method="post">
<div class="form-group">
<label for="email">Email:</label>
<input type="email" class="form-control" id="email" placeholder="Enter email" name="email">
</div>
<div class="form-group">
<label for="pwd">Password:</label>
<input type="password" class="form-control" id="pwd" placeholder="Enter password" name="pswd">
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="remember"> Remember me
</label>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>
When I open browser and go to "localhost:8080/login". It returns String "/login", not html login page. Why? Maybe I missed something to connect to my html file. I think my controller need something like an url to connect to html file. I don't understand how it work correctly. Help me please!
First, you need to modify LoginController
#Controller
public class LoginController() {
#GetMapping("/login")
public String login(Model model) {
return "/login";
}
}
If it does not work then convert html to jsp page.
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
}
Add ViewResolver to your configuration class along with your code.
You need to add a view resolver to your spring configurations.
This ViewResolver allows us to set properties such as prefix or suffix to the view name to generate the final view page URL
Example:
#EnableWebMvc
#Configuration
#ComponentScan("com.baeldung.web")
public class WebConfig implements WebMvcConfigurer {
#Bean
public ViewResolver internalResourceViewResolver() {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setViewClass(JstlView.class);
bean.setPrefix("/WEB-INF/view/");
bean.setSuffix(".jsp");
return bean;
}
}
For such simplicity of the example, we don't need a controller to process the request.
We only need a simple jsp page, placed in the /WEB-INF/view folder as defined in the configuration.
Source:
https://www.baeldung.com/spring-mvc-view-resolver-tutorial
I have been looking at all of the resources available on how to include an html file into another html file using Thymeleaf's th:insert. I am wondering if anyone could tell me what I am doing wrong as I feel like this html looks exactly like the examples I have seen.
My index.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.thymeleaf.org ">
<head>
<title>Default Page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<div th:insert="templates/Navbar :: navbar"> </div>
</body>
</html>
My Navbar.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.thymeleaf.org ">
<head>
<meta charset="UTF-8"/>
<title>NavigationBar</title>
<link rel="stylesheet" type="text/css" media="all" href="../../css/NavBar.css" th:href="#{/css/NavBar.css}" />
</head>
<body>
<div>
<div th:fragment="navbar" class="navbar">
<div class="navbar-inner">
<a th:href="#{/}" href="/home"> Home</a>
<a th:href="#{/}" href="/help">Help</a>
</div>
</div>
</div>
</body>
</html>
Also, here is my project's resource hierarchy via screen shot
If I put the code between the into the index.html and link the css file, the navbar shows up and works. So, I am not sure why the insert is not working. Here is my configuration file which has been edited based on examples below:
#Configuration
public class WebPageControllerConfig {
private SpringTemplateEngine templateEngine;
private ServletContextTemplateResolver templateResolver;
#Value("${WebController.startHour}")
public String startHour;
#Value("${WebController.endHour}")
public String endHour;
#Value("${WebController.numOfSkus}")
public int numOfSkus;
#Value("${WebController.skusToQuery}")
public File skusToQuery;
#Bean
public ClassLoaderTemplateResolver webPageTemplateResolver(){
ClassLoaderTemplateResolver webPageTemplateResolver = new ClassLoaderTemplateResolver();
webPageTemplateResolver.setPrefix("templates/");
webPageTemplateResolver.setSuffix(".html");
webPageTemplateResolver.setTemplateMode("HTML5");
webPageTemplateResolver.setCharacterEncoding(CharEncoding.UTF_8);
webPageTemplateResolver.setOrder(1);
return webPageTemplateResolver;
}
/* Old way of trying to configure
#Bean
public MessageSource messageSource() {...}
#Bean
public ServletContextTemplateResolver setTemplateResolver(){...}
#Bean
public SpringTemplateEngine setTemplateEngine() {...}
#Bean
public ViewResolver viewResolver() {...}
End of old configuration */
public String getStartHour() {return startHour;}
public String getendHour() {return endHour;}
public Object getnumOfSkus() {return numOfSkus;}
public File getSkusToQuery(){return skusToQuery;}
}
Change to
th:insert="templates/Navbar :: navbar"
and
th:fragment="navbar"
Configuration example:
import org.apache.commons.lang3.CharEncoding;
import org.springframework.context.annotation.*;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
#Configuration
public class ThymeleafConfiguration {
#Bean
#Description("Thymeleaf template resolver serving HTML 5 emails")
public ClassLoaderTemplateResolver emailTemplateResolver() {
ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("root folder where all thymeleaf files/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode("HTML5");
emailTemplateResolver.setCharacterEncoding(CharEncoding.UTF_8);
emailTemplateResolver.setOrder(1);
return emailTemplateResolver;
}
}
Try with:
th:replace="/navbar::navbar"
or
th:insert="/navbar::navbar"
It works for me. No need to specify "template/navbar".
The controller loads only a String object, but not an html page. Page login.html is in directory templates. Effect is text 'login" on page. Project is in Spring Boot.
#RestController
public class Company {
#RequestMapping("login")
public String company() {
return "login";
}
}
#SpringBootApplication
public class ComJonkSpringBootMvcApplication {
public static void main(String[] args) {
SpringApplication.run(ComJonkSpringBootMvcApplication.class, args);
}
}
<!DOCTYPE HTML>
<html>
<head>
<title>Yahoo!!</title>
</head>
<body>
Name : <input name="name" type="text" /> Password : <input name="password" type="password" /> <input type="submit" />
</body>
</html>
Do not use #RestController if you plan to return a JSP.
Use #Controller instead, and read the documentation about #ResponseBody:
Annotation that indicates a method return value should be bound to the
web response body. Supported for annotated handler methods in Servlet
environments.
I am starting to use dropzone.js and I wanted to uploaded a file and unfortunately this job doesn't work. I mention that I've been inspired from a working project.
So this is my controller class:
#Controller
public class FileUploadController {
private FileUploadService uploadService = (FileUploadService) SpringContext.CONTEXT
.getContext().getBean(FileUploadService.class);
#RequestMapping(value = { "/file" })
public String home() {
return "fileUploader";
}
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public #ResponseBody List<UploadedFile> upload(
MultipartHttpServletRequest request, HttpServletResponse response)
throws IOException {
System.out.println("Enter in upload.....");
// Getting uploaded files from the request object
Map<String, MultipartFile> fileMap = request.getFileMap();
// Maintain a list to send back the files info. to the client side
List<UploadedFile> uploadedFiles = new ArrayList<UploadedFile>();
// Iterate through the map
for (MultipartFile multipartFile : fileMap.values()) {
// Save the file to local disk
saveFileToLocalDisk(multipartFile);
UploadedFile fileInfo = getUploadedFileInfo(multipartFile);
// Save the file info to database
fileInfo = saveFileToDatabase(fileInfo);
// adding the file info to the list
uploadedFiles.add(fileInfo);
}
return uploadedFiles;
}
#RequestMapping(value = { "/list" })
public String listBooks(Map<String, Object> map) {
map.put("fileList", uploadService.listFiles());
return "/listFiles";
}
#RequestMapping(value = "/get/{fileId}", method = RequestMethod.GET)
public void getFile(HttpServletResponse response, #PathVariable int fileId) {
UploadedFile dataFile = uploadService.getFile(fileId);
File file = new File(dataFile.getLocation(), dataFile.getName());
try {
response.setContentType(dataFile.getType());
response.setHeader("Content-disposition", "attachment; filename=\""
+ dataFile.getName() + "\"");
FileCopyUtils.copy(FileUtils.readFileToByteArray(file),
response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
private void saveFileToLocalDisk(MultipartFile multipartFile)
throws IOException, FileNotFoundException {
String outputFileName = getOutputFilename(multipartFile);
FileCopyUtils.copy(multipartFile.getBytes(), new FileOutputStream(
outputFileName));
}
private UploadedFile saveFileToDatabase(UploadedFile uploadedFile) {
return uploadService.saveFile(uploadedFile);
}
private String getOutputFilename(MultipartFile multipartFile) {
return getDestinationLocation() + multipartFile.getOriginalFilename();
}
private UploadedFile getUploadedFileInfo(MultipartFile multipartFile)
throws IOException {
UploadedFile fileInfo = new UploadedFile();
fileInfo.setName(multipartFile.getOriginalFilename());
fileInfo.setSize(multipartFile.getSize());
fileInfo.setType(multipartFile.getContentType());
fileInfo.setLocation(getDestinationLocation());
fileInfo.setActuality("previous");
return fileInfo;
}
private String getDestinationLocation() {
return "D:/uploaded-files/";
}
}`
In upload method I put a message (System.out.println("Enter in upload.....")) to check if entered in this method but don't enters.
The 'fileUploader' jsp is:
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" name="viewport"
content="width=device-width, initial-scale=1">
<title>Spring MVC + Dropzone.js Example</title>
<link rel="stylesheet" type="text/css"
href='<c:url value="/web-resources/libs/bootstrap-3.1.1/css/bootstrap.min.css"/>'>
<link rel="stylesheet" type="text/css"
href='<c:url value="/web-resources/libs/bootstrap-dialog/css/bootstrap-dialog.min.css"/>'>
<link rel="stylesheet" type="text/css"
href='<c:url value="/web-resources/css/style.css"/>'>
</head>
<body>
<div class="container">
<div class="panel panel-default">
<div class="panel-heading text-center">
<h3>Spring MVC + Dropzone.js Example</h3>
</div>
<div class="panel-body">
<div>
<form id="dropzone-form" class="dropzone"
enctype="multipart/form-data">
<div
class="dz-default dz-message file-dropzone text-center well col-sm-12">
<span class="glyphicon glyphicon-paperclip"></span> <span>
To attach files, drag and drop here</span><br> <span>OR</span><br>
<span>Just Click</span>
</div>
<!-- this is were the previews should be shown. -->
<div class="dropzone-previews"></div>
</form>
<hr>
<button id="upload-button" class="btn btn-primary">
<span class="glyphicon glyphicon-upload"></span> Upload
</button>
<a class="btn btn-primary pull-right" href="list">
<span class="glyphicon glyphicon-eye-open"></span> View All Uploads
</a>
</div>
</div>
</div>
</div>
<script type="text/javascript"
src='<c:url value="/web-resources/libs/jquery/jquery-2.1.1.js"/>'></script>
<script type="text/javascript"
src='<c:url value="/web-resources/libs/bootstrap-3.1.1/js/bootstrap.js"/>'></script>
<script type="text/javascript"
src='<c:url value="/web-resources/libs/bootstrap-dialog/js/bootstrap-dialog.min.js"/>'></script>
<script type="text/javascript"
src='<c:url value="/web-resources/libs/dropzone.js"/>'></script>
<script type="text/javascript"
src='<c:url value="/web-resources/js/app.js"/>'></script>
</body>
</html>`
Now the problem is an error that appears when I press the 'upload' button after I selected a file.The error is :
<html><head><title>Apache Tomcat/7.0.57 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 405 - Request method 'POST' not supported</h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u>Request method 'POST' not supported</u></p><p><b>description</b> <u>The specified HTTP method is not allowed for the requested resource.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/7.0.57</h3></body></html>
Above error appears in browser, in console doesn't appear anything.
My servlet cod is the following:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.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.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Handles HTTP GET requests for /web-resources/** by efficiently serving
up static resources in the ${webappRoot}/resources/ directory -->
<!-- Defines a resolver implementation bean. It gets applied to all requests
handled by that DispatcherServlet -->
<beans:bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
<beans:bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<beans:property name="useTrailingSlashMatch" value="true" />
</beans:bean>
<resources mapping="/web-resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources
in the /WEB-INF/views directory -->
<beans:bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.license.web.*" />
</beans:beans>
Thanks a lot in advance!
hi i'm working in a spring mvc project and i'm getting this error when i hit the button in my form
500 (Internal Server Error) jquery.min.js:6
x.ajaxTransport.x.support.cors.e.crossDomain.send jquery.min.js:6
x.extend.ajax AddUser:19
doAjaxPost AddUser:41
onclick
i'm trying to do a simple AJAX JQuery example that adds users to a list but i get that error when i press the add button in my form
this is my controller class:
#Controller
public class UserListController {
private List<User> userList = new ArrayList<User>();
#RequestMapping(value="AddUser",method=RequestMethod.GET)
public String showForm(){
return "AddUser";
}
#RequestMapping(value="AddUser",method=RequestMethod.POST)
public #ResponseBody String addUser(#ModelAttribute(value="user") User user, BindingResult result )
{
String returnText;
if(!result.hasErrors())
{
userList.add(user);
returnText = "User has been added to the list. Total number of users are " + userList.size();
}
else
{
returnText = "Sorry, an error has occur. User has not been added to list.";
}
return returnText;
}
#RequestMapping(value="ShowUsers")
public String showUsers(ModelMap model)
{
model.addAttribute("Users", userList);
return "ShowUsers";
}
}
and this is my AddUser.jsp page
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Add Users using ajax</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<!-- <script src="resources/js/libs/jquery-2.0.2.min.js"></script> -->
<script type="text/javascript">
function doAjaxPost() {
// get the form values
var name = $('#name').val();
var education = $('#education').val();
$.ajax({
type: "POST",
url: "AddUser",
data: "name=" + name + "&education=" + education,
success: function(response){
// we have the response
$('#info').html(response);
$('#name').val('');
$('#education').val('');
},
error: function(e){
alert('Error: ' + e);
}
});
}
</script>
</head>
<body>
<h1>Add Users using Ajax ........</h1>
<table>
<tr><td>Enter your name : </td><td> <input type="text" id="name"><br/></td></tr>
<tr><td>Education : </td><td> <input type="text" id="education"><br/></td></tr>
<tr><td colspan="2"><input type="button" value="Add Users" onclick="doAjaxPost()"><br/></td></tr>
<tr><td colspan="2"><div id="info" style="color: green;"></div></td></tr>
</table>
Show All Users
</body>
</html>
and my MvcConfiguration class since i'm using a java based configuration and not using XML
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = { "controllers" })
public class MvcConfig extends WebMvcConfigurerAdapter
{
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
// JSP VIEW-RESOLVER
#Bean
public InternalResourceViewResolver jspViewResolver() {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setOrder(2);
bean.setPrefix("/WEB-INF/views/");
bean.setSuffix(".jsp");
return bean;
}
}
EDIT: i starter a new project just for the sake of trying to know what error i'm having, i delete spring secuirty in my application, but i still can figure out whats wrong.
1) i actually dont delete spring security i just starte a new project to try to solve my url problem
2) i change my controllers and the URL attribute in my ajax script
new RequestMapping controllers:
#RequestMapping(value="AddUser",method=RequestMethod.GET)
i deleted the "/" in the value="AddUser"
i dont have a "/" in any of my controllers if put a "/" in the controllers i have the same 500 Internal server error
This might be because of the CSRF protection which is enabled by default in Java configuration. Try in your configuration...
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// ...
.csrf().disable();
}
Let me know if this works.
EDIT**
To include CSRF token in AJAX request, if you are using JSON, you need to put it on the http header. Sample JSP example typically would be...
<html>
<head>
<meta name="_csrf" content="${_csrf.token}"/>
<meta name="_csrf_header" content="${_csrf.headerName}"/>
</head>
Then in your javascript call, get this parameters and add it to XMLHttpRequest's header.
Hope this helps.
Further reading
In my case, i had to add the below dependency to my pom
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.2.2</version> </dependency>