I am new to AngularJs & Spring. I am calling Spring MVC GET Method from AngularJs function. Sometime GET method is not called up and giving old session values. If i use POST its working fine.
Please comment if need more details about it.
Spring MVC method :
#RequestMapping(value="/getAccessDetails", method=RequestMethod.GET)
public #ResponseBody ProcessDO getAccessDetFromSession(HttpServletRequest request){
AccessDO accessDO = null;
HttpSession session=request.getSession();
if(session.getAttribute("accessDetail")!=null) {
accessDO =(AccessDO) session.getAttribute("accessDetail");
}
return accessDO ;
}
AngularJS Function :
$scope.loadDetails = function(){
$http.get(CONTEXT+'/getAccessDetails').then(function(resp){
alert(resp.data); // Getting old value
});
};
Targets of caching operations
I think this explains your issue.
This is happening because your response is getting cached and when you are trying again you are getting cached response in case of GET.
While post method doesn't get cached neither it get saved in browser history.
you can also referhttp_methods_get_post_difference this link
Related
TLDR: My method requires 2 redirects/forwards to work (1 for authentication and 1 to serve the jsp page). How can I resolve both redirects/forwards (or make it a non-requirement) so as to not run into the error, java.lang.IllegalStateException: Cannot forward after response has been committed.
For more context:
I have a java servlet with a method that looks something like the following:
#GET
#Path("/test")
#Authenticate
public Viewable test(#Context HttpServletRequest request, #Context HttpServletResponse response) {
Map<String, Object> model = createModel();
return new Viewable("/somePath/jspFile", model);
}
The #Authenticate annotation intercepts the call to do some Open ID Connect type authentication which results in the user being forwarded to a different server for all authentication needs. If the user is authenticated, they are redirected back to my application.
However, when hitting the url for this method, I am getting java.lang.IllegalStateException: Cannot forward after response has been committed. I don't know too much about using this Viewable class, but based on the fact that I don't run into that error when returning String/void/whatever else, I assume returning a new Viewable needs to do some forwarding that results in the user seeing the jsp page.
I've read the main SO post about this error, but I am unsure how to apply the fixes to my current problem. For example, I don't know how I would apply something like the following fix:
protected void doPost() {
if (someCondition) {
sendRedirect();
} else {
forward();
}
}
The fix assumes that I can I can either redirect OR forward, but my current method needs a redirect for authentication AND a forward/redirect to serve the jsp page. Maybe there's an obvious fix I'm missing that doesn't require a complete rehaul of the current code?
Edit: It would be nice if I could check if the user was authenticated first, but I assume using this annotation at all automatically entails an initial redirect
Edit: It looks like the user is redirected for the initial login authentication, but does not need to be redirected again after being authenticated once due to SSO
Ok based on some preliminary testing, it seems like the following solution has worked for me:
Check if the user has already been authenticated
Return a Response rather than a Viewable.
Since the user only needs to be redirected the first time for authentication, I can return an empty/meaningless response as a placeholder. And then once the user has been authenticated and is returned to my app, I can return a Viewable wrapped in a Response object.
So the code would look something like the following:
#GET
#Path("/test")
#Authenticate
public Response test(#Context HttpServletRequest request, #Context HttpServletResponse
response) {
Map<String, Object> model = createModel();
if (userIsAuthenticated()) {
return Response.status(401).build();
} else {
return Response.ok(new Viewable("/somePath/jspFile", model)).build();
}
}
I am trying to pass data from DAO to JSP using ModelMap. It works but, when I refresh that page, same data comes repeatedly on every refresh. I want data not to come again and again on refreshing the page. Help me for this issue.
#Autowired
private SelectInfo selectInfo; /* Instance of SelectInfo DAO class injected here, here the method of fetching data from databse is defined and fetched data is passed to GetInfo bean*/
#Autowired
private GetDetail getDetails; /* GetDetail is the bean where the values are stored which are coming from database */
#RequestMapping(value="/selectInfo", method=RequestMethod.GET)
public String registerComplete(ModelMap model,HttpSession session,HttpServletResponse res) {
if(session.getAttribute("user")==null) {
return "redirect:/";
}else {
selectInfo.getInfo(); /*getInfo is the method defined in SelectInfo class which fetch data from database*/
/* the values are adding in modelmap using getter method from GetInfo bean */
model.put("cities", getDetails.getCities());
model.put("theaters", getDetails.getTheaters());
model.put("movies", getDetails.getMovies());
model.put("dates", getDetails.getDates());
model.put("timings", getDetails.getTimings());
return "cities";
}
So you do not want call your db each time when page refreshes? I think you can try caching in that case. Please take a look at example here: https://spring.io/guides/gs/caching/
You can just add annotation on your controller method.
#RequestMapping(value="/selectInfo", method=RequestMethod.GET)
#Cacheable
public String registerComplete(ModelMap model,HttpSession session,HttpServletResponse res) {
//your code goes here
}
If you are passing the data using modelMap means, data will be transferred each time a page load or refreshed. In order to load the data once use ajax and sessionStorage
Create new method in controller class to return data like this
#RequestMapping(value="/cities", method=RequestMethod.GET)
public #ResponseBody Object registerComplete(){
return getDetails.getCities()
}
In javascript check the sessionStorage if its null then load the data using ajax.
$(document).ready(function(){
if(sessionStorage.cities ==null){
$.ajax({
type : 'GET',
url : "/cities",
contentType:'application/json',
data:JSON.stringify(data),
success : function(response) {
sessionStorage.cities =response;
}
});
}
}) ;
By this you can restrict data load on each refresh
Caching is the natural way to avoid unnecessary trips to database. Spring provides support for this using #Cacheable annotation.
If you are using Spring Boot, things are easier for you. Ensure that you have got spring-boot-starter-cache in your dependencies or one of your spring starters depends on spring-boot-starter-cache. Then you can annotate your DAO method like so:
#Component
public class SelectInfo {
...
#Cacheable("dbInfo")
public <returnType> getInfo() {
// Implementation of the method
}
...
}
Putting the Cacheable annotation over the method in your DAO is advised since it is responsible for fetching the actual data that you want to cache.
If you are not using Spring Boot, you'll have to include a Cache Provider and configure a bean for that provider. The details of how to do this can be found in the Spring Caching Docs https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-caching.html#boot-features-caching-provider
#RequestMapping("/modify")
public String modifyAd(AdDto adDto, Model model){
if (adService.modifyAd(adDto)){
adDto.setTitle("");
model.addAttribute(PageCodeEnum.KEY,PageCodeEnum.MODIFY_SUCCESS);
}else {
model.addAttribute(PageCodeEnum.KEY,PageCodeEnum.MODEFY_FAILED);
}
return "forward:search";
}
The adDto.title I got from jsp is '芒果冰淇淋11',
I have set Title to ""
#RequestMapping(value = "/search",method = RequestMethod.POST)
public String queryByTitle(AdDto adDto, Model model){
List<Ad>adList = adService.queryByTitle(adDto);
model.addAttribute("adList",adList);
model.addAttribute("searchParam",adDto);
return "/content/adList";
}
But after forward, adDto.title doesn's change. I don't know why.
You can see the 'title' change to "芒果冰淇淋11"
I think this response on another question may be helpful:
Spring forward with added parameters?
re-adding what you need to the request before it is forwarded.
Using FlashScope as well should be an option here an example:
https://www.javacodegeeks.com/2012/02/spring-mvc-flash-attributes.html
(in the example it uses "redirec:some/path" but using "forward" as you do should be possible as well)
A link to Spring (4.1) docs for Flash attributes:
https://docs.spring.io/spring/docs/4.1.x/spring-framework-reference/html/mvc.html#mvc-flash-attributes
I finally solved this problem in adding the following code:
Code
I want to return a model from my Spring MVC controller, which will be visible to all pages in my application.
So, I need a variable which return some user details.
This is my code:
#RequestMapping(value = "/*", method = RequestMethod.GET)
public void status(Model model){
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
String username = auth.getName();
Manager mgr = managerService.findOne(username);
model.addAttribute("buget", mgr.getTeam().getTeamBuget());
}
And in my jsp page, i write something like this:
<li> <c:out value="${buget}" /> <span class="glyphicon glyphicon-euro"></span></li>
I want to be able to print the ${buget} in every page from my app.
So, my method don't work, nothing is appear in my pages and the biggest problem
for me is that I don't get any exceptions or errors which could help me. Who can help me with some advices?
I'm not entirely sure what it is that you're trying to do. Do you mean that you want buget to be part of every page that you hit? If so, you have to insert it into the model. Based on your code, I'm assuming that you have the mistaken impression that status is going to be called regardless of whatever page you hit. Spring will resolve to the most-specific handler and so if you have another handler method in another controller that is more specific, Spring will use that. But even if the one you have was called, how would Spring know that it has to call the most-specific one next? So how would you add page-dependent model attributes to the model?
If you want buget to be part of every response, you can use #ControllerAdvice (see here for a blog post with more details):
#ControllerAdvice
public class BugetControllerAdvice {
#ModelAttribute
public void addBugetToModel(Model model) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
Manager mgr = managerService.findOne(username);
model.addAttribute("buget", mgr.getTeam().getTeamBuget());
}
}
Spring will now call this method before every handler-method in every controller. You can also take a look at the Spring Reference for more information.
I am unable to get the ModelAttribute for second request.
My first request is initForm() method I prepared Command object and able to display the command in jsp.
Through initForm() I am populating command and that command I want in editForm when I will do ajax call.
Here is my spring form
<form:form method="POST" action="addstudentdetails.htm" commandName="command">
Ignore what is inside this
Name: Shoaib Age:23 edit
</form:form>
My ajax request:
function editStudentDetails(studentId,index){
$.ajax(
{url:"editstudentdetails.htm",
method:"GET",
data:{"action":"edit","id":studentId,"index":index},
success: function(data) {
jQuery("#studentDetailsDiv").html(data)
}
}
)
}
In editStudentDetails() method I have method ajax call to go editForm() of the controller.
Here is my controller:
#Controller
public class StudentDetailsController {
#Autowired
private StudentDetailsDAO studentDetailsDAO;
#RequestMapping(value="/studentdetails.htm",method = RequestMethod.GET)
public String initForm(HttpServletRequest request,ModelMap map){
String action=request.getParameter("action");
StudentDetailsCommand command=new StudentDetailsCommand();
System.out.println("in controller"+action);
command.setStudents(studentDetailsDAO.findAll());
map.addAttribute("command", command);
return "studentdetails";
}
#RequestMapping(value="/editstudentdetails.htm",method = RequestMethod.GET)
public String editForm(ModelMap map,HttpServletRequest request){
map.addObject("index", request.getParameter("index"));
StudentDetailsCommand command=(StudentDetailsCommand)map.get("command");
System.out.println(command);
System.out.println(command.getStudents());//NullPointerException here.
map.addObject("command", command);
return "studentdetails";
}
}
Even tried #ModelAttribute("studentDetailsCommand") but didn't worked.
I am new to Spring 3.0 and I followed all solutions which are given here but nothing worked.Can anyone help me out please?
Model attributes only exist during the life cycle of one HttpServletRequest. Consider reading my answer here.
In your initForm method, you do the following
map.addAttribute("command", command);
this add an attribute named command to the model attributes. This attribute will eventually find its way into the HttpServletRequest attributes and be available to your JSP. In here
<form:form [...] modelAttribute="studentDetailsCommand" commandName="command">
first of all, modelAttribute and commandName have the same purpose, ie. to find an attribute in the model. If you remove commandName you will get an Exception because there is no model attribute named studentDetailsCommand. Here your commandName's value is overwriting your modelAttribute's value.
When the Servlet container is finished rendering your JSP, the rendered content is sent as the body of the HTTP response. At this point, the request has been handled and the HttpServletRequest and the model attributes are garbage collected.
When you send your new request through AJAX, there is no longer any model attribute named studentDetailsCommand (there actually never was).
Consider using Flash Attributes.
Related:
How to read flash attributes after redirection in Spring MVC 3.1?
Spring RedirectAttributes: addAttribute vs addFlashAttribute
Use of getFlashAttributes() in Spring's RedirectAttributes