Alternative of URL parameter for deciding which method to call - java

Right now based on the site name in the URL parameter, we decide the appropriate actions to take(method calls etc) in the Java (Standard Jsp/Servlet web applications). For example, the request would be something like www.oursite.com?site=Ohio
Wondering what would be the alternative of doing this without having to provide URL parameter.

You could use POST instead of GET.
GET appends request parameters to the end of the URL.
POST sends encoded data using a form.
http://www.tutorialspoint.com/jsp/jsp_form_processing.htm

Why not just code it into the path?
www.oursite.com/Ohio
If you're just using straight servlet api, you can just do something of this nature:
String path = request.getPathInfo();
String site = path.split("/")[0];
That being said, most web frameworks have some support for helping with this.
For example, in spring mvc:
#RequestMapping(value="/{site}/blah/blah", method=RequestMethod.GET)
public ModelAndView blahBlah(HttpServletRequest req,
HttpServletResponse resp,
#PathVariable("site") String site) {
// do stuff here
}
Of course you could do this at the controller level too if all your methods need that sort of mapping:
#Controller
#RequestMapping(value="/{site}")
public class MyController {
#RequestMapping(value="/blah/blah", method=RequestMethod.GET)
public ModelAndView blahBlah(HttpServletRequest req,
HttpServletResponse resp,
#PathVariable("site") String site) {
// do stuff here
}
}
I believe this is cleaner than a query param, though it still shows up in your URL. There's other, more complex methods like using apache's reverse proxying and virtual host capabilities to switch based on site names. You could do something at login, and store the site in session. It all depends on your requirements.

You could use an alternate URL, like ohio.oursite.com. This process could be automated by having your server respond to *.oursite.com. I would probably set up a filter that looked at what the subdomain was and compared that with a predefined list of allowed sites. If it didn't exist, you could redirect back to the main (www) site. If it did, you could set a request attribute that you could use in a similar way that you currently use the request parameter now.

Related

Forwarding request to a new controller

I have this two controller from two separate projects lets name them:
project1.controller1
project2.controller1
Obviously these are two Spring controllers from different projects.What I want is to make project1.controller1 a gateway all request will be sent here. And will process the request if it will go to project2.controller1 or a new controller.
Some pseudoCode:
#Controller
public class someClassFromProject1{
#RequestMapping(value="/controller1", method=RequestMethod.POST)
public String smsCatcher(String target, HttpServletRequest request,
HttpServletResponse response){
//some processing, converting request to string, etc
if("someStringThatIsPartOfTheRequest".equals("someString"))
//carry request and forward it to project2.controller1
else
//go to another external controller
}
}
And in project2.controller 1 will look something like this:
#Controller
public class someClassFromProject2{
#RequestMapping(value="/controller1", method=RequestMethod.POST)
public String smsCatcher(String target, HttpServletRequest request,
HttpServletResponse response){
//processing
}
}
I've already tried return "forward:/someUrl"; and return "redirect:someUrl";. It didn't work and it didn't reach project2.controller1. So any ideas on this one?
Edit: Forgot to add this one, different project means different WAR but deployed on the same sever. And the request should be carried over from project1.controller1 to project2.controller1 because I'm gonna process the request there.
Thanks!
You need to use redirect instead of forward.
The protocol is required if the host is different to that of the current host
return "redirect:http://www.yahoo.com";
Have a look at the redirect: prefix section from Spring Web MVC framework also check this
A logical view name such as redirect:/myapp/some/resource will
redirect relative to the current Servlet context, while a name such as
redirect:http://myhost.com/some/arbitrary/path will redirect to an
absolute URL.
Figured it out but then it's kind of messy, I've used HttpClient to Post my Request to the URL. It also carried the request along with the forwarding. Anyway, thanks for all the help guys. Thanks :)

How to design the API such that it reads HTTP header if parameters are not present?

In a controller class,
I have one method
#RequestMapping(value="test", method={RequestMethod.POST,RequestMethod.PUT})
#ResponseBody
public String testApp(#RequestParam String priceA, #RequestBody String valueOfProduct) throws Exception {
}
My client is sending prices to my App as POST requests for processing.
Now client (which is not under my control) is planning to send the price value as a request parameter and another client is planning to send price in requestheader.
The trick is:
If it is present in requestheader it wont be present in requestparameter.
So I have to design it such that my server code works fine in both cases.
Kindly let me know which design would be the best.
Will it be
#RequestMapping(value="test", method={RequestMethod.POST,RequestMethod.PUT})
#ResponseBody
public String testApp(#RequestParam String priceA, #RequestHeader("PRICE") String priceAFromAnother, #RequestBody String valueOfProduct) throws Exception {
}
But above logic wont work as #RequestParam wont be available all the time.
Have you tried searching by your own first?
Take a look that this answer.
If you know the header to search for, you could add a request filter (HttpServletRequestWrapper) that pre-process the request. Here is simple example Modify request parameter with servlet filter
NOTE: I would caution you that this methodology is not maintainable if your parameter set/api is going to grow over time.

Using only one servlet

I'am making a web page with a login system and backoffice page. The problem is, both use the method "doPost" (the login use to autenticate and the backoffice use to insert data in db). How can I use only one servlet for both? I'am asking this because both use doPost, so I made two servlet's.
In case you want to use a single servlet, you should implement Front Controller Pattern. For this, you will parse the request URL and decide which action should be performed:
public class MySingleServlet extends Servlet {
#Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String url = request.getPathInfo();
//returns the action to handle
Action action = ActionFactory.getAction(url);
action.process(request, response);
}
}
This involves an Action interface/abstract class and an ActionFactory that will parse the URL and return the right implementation to handle the actions to do.
Another more naive and harder-to-maintain implementation is by sending an action parameter. This may be a problem because an attacker may use a proxy and change the action parameter before sending the request to the URL. If this is a recognized valid action, and the attacker knows what to send, then you're in trouble.
Note that there are MVC frameworks that already implement Front Controller Pattern like Spring MVC and JSF, so there's no need to reinvent the wheel unless it is for learning purposes (otherwise, you should use a library that already implements this).
You could add an extra parameter (e.g. action) in your post method
retrieved from a hidden form field, if you are using forms, or
added with a simple &action='value' to your request if using xml http request
and based on its value perform the appropriate actions:
if (action.equals("auth"))
{
// authenticate
}
else if (action.equals("backoffice"))
{
// db update
}
You can get pathInfo from request object based on that you route the request.

Spring MVC webapp link to excel document and rename it

I have a question about whether or not something is possible. I have a spring mvc webapp that will have a button that links to an external website which returns an Excel document. The name of the excel document returned is rubbish and I would like to rename the document as it comes in before the user is prompted to save.
Is this possible using spring mvc. I'm on a really old version. The version compatible with Java 1.4.2.
So far I'm thinking that I'll extend org.springframework.web.servlet.mvc.AbstractController, override handleRequestInternal and then do something like this....
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();
urlBuilder.setServerName(batchServerName);
urlBuilder.setPort(Integer.parseInt(batchServerPort));
urlBuilder.setContextPath(batchReportRoot);
urlBuilder.setServletPath(reportNameServletPath);
urlBuilder.setPathInfo(reportNamePathInfo);
urlBuilder.setScheme(HTTP);
String transitionUrl = urlBuilder.getUrl();
ModelAndView modelAndView = new ModelAndView(new RedirectView(transitionUrl));
return modelAndView;
But how do i take it further to rename the document as it comes in etc...
thanks
Perhaps another approach you might consider is that you have a Controller implementation that proxies the request onto the external website. Rather than interacting with the external website directly, your users interact with your Controller. This will give you the opportunity to re-name the file before it is served to your users. It also means that should things change in the future, you only need to change the implementation of your Controller.
So a proposed work flow could be:
User clicks link to your controller /downloadExcelReport
The request is handled by ExcelReportController
ExcelReportController makes an HTTP request to the external website and fetches the Excel document
Before returning the Excel report to your user, ExcelReportController sets the correct HTTP headers to ensure that the file is named according to what you need.
This way you're only providing a normal Controller implementation rather than having to override the internals of Spring.

I can't get google cloud endpoints to work correctly, am I calling the correct public link?

The api is tagged:
#Api(version = "v1",
description = "API for interfacing with accounts",
defaultVersion = AnnotationBoolean.TRUE)
and one of the methods I want to call is:
#ApiMethod(name = "account.register",
path = "account",
httpMethod = HttpMethod.POST)
public void register(HttpServletRequest request, HttpServletResponse response)
{ ...
but I can't seem to figure out the url to access it :(
I tried POST-ing to myapp.appspot.com/_ah/api/myapi/v1/account but it 404's
A few things...
I think one doesn't usually use Endpoints this way: by posting manually to a URL. Instead, you are expected to generate a client library (which encapsulates the URL) and then use the client library.
If you just want to check out your endpoints, I've heard that the API explorer is very useful. For your specific application you'd use:
https://myapp.appspot.com/_ah/api/explorer
and be redirected to a version of the APIs Explorer for your application.
The actual calls to your App Engine backend are to paths such as this: /_ah/spi/MyEndpoint.myMethod. (Note: the spi versus api in the path.) The actual path you tried to construct is Google's API serving infrastructure acting as a frontend to your application.
You do not have any (HttpServletRequest request, HttpServletResponse response) in an endpoint.
The easiest thing to do is to make your java class (which you want to persist) and then in eclipse point at the java class and right click and select "google -> generate google cloud endpoint class" Then you get a good idea how it looks in different scenarios.
If you want to send parameters you have to add for instance myMethod( #Named( "myName" ) String name ).
But check out the endpoint genration first, it makes it all much simpler
And look here for more info: https://developers.google.com/appengine/docs/java/endpoints/annotations

Categories