Not able to access SpringContext after integrate Atmosphere framework with spring MVC - spring-mvc

As I mentioned in the title that After integrating Atmosphere framework with Spring MVC, I want to access current LoggedIn User by the help of SecurityContext(Or Authentication), But gives me null when I send the ajax request from the JSP page(client side).
Is there any problem with my code or some other problem. Below are my MyController.java and JSP files
MyController.Java
#Controller
public class MyController {
#Autowired
PartyManagementService partyManagementService;
#RequestMapping(value = "/websockets", method = RequestMethod.POST)
#ResponseBody
public String post(final AtmosphereResource event, #RequestBody String message)
throws JsonGenerationException, JsonMappingException, IOException {
User user = (User)SecurityContextHolder.getContext().
getAuthentication().getPrincipal();
String username = user.getUsername();
Person person = partyManagementService.getPersonFromUsername(username);
logger.info("Received message to broadcast: {}", message);
final int noClients = event.getBroadcaster().getAtmosphereResources().size();
event.getBroadcaster().broadcast(message);
return " message successfully send ";
}
}
home.jsp
In my home jsp, I provide ajax request which pushes the message to the server.

Related

SpringWebMvcTest - Test Requestbody using #Valid and custom validation

I am trying to test my controller endpoint and my requestbody annotated with #Valid annotation. My Testclass looks like the follow:
#RunWith(SpringRunner.class)
#WebMvcTest(value = BalanceInquiryController.class, secure = false)
public class BalanceInquiryControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private BalanceInquiryController balanceInquiryController;
#Test
public void testGetBalanceInquiry() throws Exception {
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/com/balanceInquiry")
.accept(MediaType.APPLICATION_JSON)
.content("{\"comGiftCard\":{\"cardNumber\":\"1234567890\",\"pinNumber\":\"0123\"},\"comMerchant\":\"MERCHANT1\"}")
.contentType(MediaType.APPLICATION_JSON);
MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = mvcResult.getResponse();
assertEquals(HttpStatus.OK.value(), response.getStatus());
}
}
My Controller - #PostMapping looks like that:
#PostMapping(value = "/com/balanceInquiry")
public ResponseEntity<?> getBalanceInquiry(#Valid #RequestBody BalanceInquiryModel balanceInquiry, Errors errors) {
if (errors.hasErrors()) {
return new ResponseEntity<String>("Validation error", HttpStatus.BAD_REQUEST);
}
//do any stuff...
return new ResponseEntity<BalanceInquiryResponse>(balanceInquiryResponse, HttpStatus.OK);
}
My BalanceInquiryModel is annotated with #Valid and has some hibernate and custom validations behind. Those validations are all ok and already unit tested.
What I like to test is my endpoint where I send a valid json request body expecting a 200 response and also an invalid json request body expecting a 400 response validated by the set #Valid implementation.
For example an unvalid call is to send no pinNumber or length < 4.
I have read some threads and some uses MockMvcBuilders.standaloneSetup() to mock the full controller. But I wont do a full integration test.
Not quite sure how to go on with this situation and if I should go on.
P.S.: At the moment I get always a 200 response no matter if the validation should give an error or not.
Here a gist for more code and the validation classes/models.
Here's one of my example I work on my project
hope it help you out:
I have a global exception handler to handler my MethodArgumentNotValidException and throw it
#RequestMapping(value = "/add", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> createUser(#Valid #RequestBody User user) {
User savedUser = userService.save(user);
return new ResponseEntity<User>(savedUser, HttpStatus.CREATED);
}
public void testAdduser() throws Exception{
final User request = new User();
request.setFirstName("Test");
request.setLastName("some description");
mockMvc.perform(post(END_POINT+"/add")
.contentType(MediaType.APPLICATION_JSON)
.content(stringify(request))
).andDo(print()).andExpect(status().isUnprocessableEntity())
;
}
private String stringify(Object object) throws JsonProcessingException {
return new ObjectMapper().writeValueAsString(object);
}
Update:
I think your main problem is that you are using #WebMvcTest in stead of #SpringBootTest.
the different between 2 of them is that:
#SpringBootTest annotation will loads complete application and injects all the beans which is can be slow.
#WebMvcTest - for testing the controller layer. it doesn't inject other bean beside the #RestController
so if you are just testing just pure controller to see u can reach the endpont then you can just use #WebMvcTest which will make your test run faster.
but in your case, you want it to run the spring validation, you will need to use #SpringBootTest
for detailed: https://spring.io/guides/gs/testing-web/

Spring MVC session resource is getting shared by logged users

I have deployed a web application using Apache tomcat 8, java 8 and centos server in production.
When i tested the system by 5-6 users concurrently in office network everything seemed ok. But in client network, one users info is getting by another user(session attributes are shared/mixup). For example, if user A logs in, after a while his name is showing user B, who is logged in from different computer. If user presses Ctrl+R then his/her previous session restores for a while.
N.B. this scenario never happens other than that client network. They are using specific proxy. Other than proxy, this scenario does not happen.
I have a simple LoginController class without defining any scope. Some code snippets are below:
1. Login GET method:
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String getLogin(#ModelAttribute LoginForm loginForm)
{
return "login";
}
2. Login POST method:
#RequestMapping("/login", RequestMethod.POST)
public String Login(#ModelAttribute LoginForm loginForm, HttpSession session)
{
User dbUser = this.userService.getUser(loginForm.getUserID());
if (dbUser != null)
{
if(passwordCheckedSuccess(dbUser.getPassword(), loginForm.getPassword()))
{
session.setAttribute("userName", dbUser.getUserName());
session.setAttribute("userId", dbUser.getUserId()); // primary key of user class
return "dashboard";
}
else
{
return "login";
}
}
}
3. I have created a loginIntercptor class to filter secured pages:
public class LoginInterceptor extends HandlerInterceptorAdapter
{
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
if (!request.getRequestURI().endsWith("/login"))
{
if (request.getSession().getAttribute("userId") == null)
{
response.sendRedirect(request.getContextPath() + "/login");
return false;
}
}
return true;
}
}
I am not using spring security.
Please suggest a way to get rid of it. Thanks.

URL with hash in Spring Mvc

everyone.
I'm using Spring MVC 4. My App sends activation url to user's email.
Activation url:
www.example.com:8080/myapp/user/activate/$2a$10$Ax2WL93zU3mqjtdxuYlYvuWWyQsPBhkhIfzYHJYk4rdNlAY8qCyC6
But, my App can't find path.
My controller:
#RequestMapping(value = "/user/activate/{hash})
public void activateUser(#PathVariable("hash") String hash) {
userService.activate(hash);
}
What am I doing wrong?
Update:
I've found out that if hash contains dot (".") then throws 404 error.
I've change my url:
www.example.com:8080/myapp/user/activate?code=$2a$10$Ax2WL93zU3mqjtdxuYlYvuWWyQsPBhkhIfzYHJYk4rdNlAY8qCyC6
and my controller:
#RequestMapping(value = "/user/activate)
public void activateUser(#RequestParam("code") String hash) {
userService.activate(hash);
}
It works perfectly.
you are not returning anything from the controller, hence receiving a 404
If you have dot (.) in your path variable value, then you must declare it explicitly in the RequestMapping, as shown below -
#RequestMapping(value = "/download/{attachmentUri:.+}", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<InputStreamResource> downloadAttachment(#PathVariable("attachmentUri") String attachmentUri,
HttpServletResponse response,
WebRequest webRequest) {
}

Spring 3 MVC : move/share model from Controler to another Controler

I'm doing a little project with Spring 3 MVC & jQuery
I'm not sure how to ask it so i'll try to explain
I have this scenario :
LoginPage(with User object model) ---submit--> Server sends OK back to LoginPage -->
(LoginPage) redirect to Page2 using window.location = "Page2"
Problem : Page 2 doesn't recognize User
How to make it work? I tried reading about #SessionAttributes but didn't really understand it.
#Controller
public class LoginController {
...
...
#RequestMapping(value = "/")
public ModelAndView loginPage(ModelMap model) {
model.addAttribute("user", new User());
logger.info("Loading Login Page");
return new ModelAndView("login");
}
#RequestMapping(value = "/loginSubmit.html" ,method=RequestMethod.GET)
public String processSubmit( ModelMap model, User user) throws InterruptedException{
...
...
return "1" to login page
...
...
Here I want User user to be known from last controller,but it's making a new one instead.
#Controller
public class Controller2 {
#RequestMapping(value = "/home")
public String home(ModelMap model, User user) {
...
...
}
LoginPage.jsp
$.get("loginSubmit.html", form1Var.serialize(), function(data){
var isSucess = data.charAt(0) == "1" ? true : false;
if ( isSucess == true) {
alert("ok...");
window.location = "home";
}
EDIT Moved my solution to Answers.
By default the server side in Spring MMVC is stateless. To save state between requests you must put the data you want to save in the session. This data is then available for every request in the same session (i.e. from the same client).
In the solution you found, the #SessionAttributes("user") annotation has told Spring MVC to that you want the user object to be persisted across requests by saving it in the session. This is how Spring abstracts you from all the work of actually maintaining the state yourself.
My Solution :
#SessionAttributes("user")
on both controllers
and
#ModelAttribute("user") User user
as param in the method - worked
I'v also added
#ExceptionHandler(HttpSessionRequiredException.class)
public String SessionException(HttpSessionRequiredException ex) {
logger.info(ex.getMessage());
return "redirect:LogIn";
}
to catch Exception and the user will go to LoginPage instead of a exception error page
As Donal Boyle pointed , conclusion : use #SessionAttributes to share models between Controllers

Why am I getting 400 and 405 exceptions with my WCF RESTful client application with PUT and POST?

I am building an application that has a two server setup - a "services" server and a "front end" server. The "services" server has a WCF service. The "front end" server has a traditional ASP.NET web forms application that accesses the WCF service. I can get the GET requests to work fine. However I can't seem to get any PUT or POST requests to work. When I try to issue a POST I get a 400 exception - Bad Request. When I try to issue a PUT I get a 405 exception - Method Not Allowed. I feel like I have everything set up correctly - but obviously not. Here is the code for my WCF service:
Service.svc:
<%# ServiceHost Language="C#" Debug="true" Service="TestSvc" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
TestSvc.cs:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceContract]
public class TestSvc
{
[WebGet(UriTemplate="/")]
[OperationContract]
public Users GetUsers()
{ ...code to get all users from database }
[WebInvoke(UriTemplate = "/", Method = "POST")]
[OperationContract]
public void AddUser(User user)
{ ...code to add user to database }
[WebInvoke(UriTemplate = "/{id}", Method = "PUT")]
[OperationContract]
public void UpdateUser(string id, User user)
{ ...code to update user in database }
[WebGet(UriTemplate = "/{id}")]
[OperationContract]
public User GetUser(string id)
{ ...code to get a single user from database }
}
(In addition I have classes for the User and Users entities)
Then on the front end I have this interface:
[ServiceContract]
interface ITestService
{
[WebGet(UriTemplate = "/")]
[OperationContract]
Users GetUsers();
[WebInvoke(UriTemplate = "/", Method = "POST")]
[OperationContract]
void AddUser(User user);
[WebInvoke(UriTemplate = "/{id}", Method = "PUT")]
[OperationContract]
void UpdateUser(string id, User user);
[WebGet(UriTemplate = "/{id}")]
[OperationContract]
User GetUser(string id);
}
And then I have this helper class:
public class ServiceClient
{
WebChannelFactory<ITestService> cf;
ITestService channel;
public ServiceClient()
{
cf = new WebChannelFactory<ITestService>(new Uri("http://myserver/service.svc"));
channel = cf.CreateChannel();
}
public Users GetUsers()
{ return channel.GetUsers(); }
public User GetUser(string id)
{ return channel.GetUser(id); }
public void AddUser(User user)
{ channel.AddUser(user); }
public void UpdateUser(string id, User user)
{ channel.UpdateUser(id, user); }
}
And finally here is what the code behind looks like on my page that is trying to do an update of a User object.
protected void btnSave_Click(object sender, EventArgs e)
{
User _user = new User(Convert.ToInt32(txtID.Value), txtFirstName.Text, txtLastName.Text, Convert.ToInt32(txtAge.Text), chkIsRegistered.Checked);
ServiceClient _client = new ServiceClient();
_client.UpdateUser(txtID.Value, _user);
Response.Redirect("~/ViewUsers.aspx");
}
When I run the front end project and try to do an update I get the following error:
The remote server returned an unexpected response: (405) Method Not Allowed.
Any ideas? Thanks, Corey
How much data are you sending? I have had trouble with WCF services when sending more than 64k at a time (with the default configuration, you can increase it). POST would typically return a 400 in this case, but I don't know what PUT would return, since my service doesn't use PUT.
I solved part of the problem. I deleted the WebDav module in IIS for the site and then the PUT began to work. (I think it has to do with WebDav handling the PUT and DELETE verbs) However the POST verb is not working. It is returning a 400 Bad Request error. I will try solving that in a separate question.

Resources