Jersey Namebinding technique in Spring Boot Rest - java

I have seen the name binding strategy from jersey to shield the api, it's pretty cool for authentication, and it's pretty cool to just annotate the endpoints you want to authenticate, and in jersey you can bind the annotation to the filter.
does anybody knows how to achieve this in spring boot ?

Check maven dependencies
Check the maven file should have spring-boot-starter-jersey dependency in it.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Create REST APIs
Now create some JAX-RS resources which we will access into testing phase. I have created UserResource class.
UserResource.java
package com.howtodoinjava.jerseydemo;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "users")
#Path("/users")
public class UserResource
{
private static Map<Integer, User> DB = new HashMap<>();
#GET
#Produces("application/json")
public Users getAllUsers() {
Users users = new Users();
users.setUsers(new ArrayList<>(DB.values()));
return users;
}
#POST
#Consumes("application/json")
public Response createUser(User user) throws URISyntaxException
{
if(user.getFirstName() == null || user.getLastName() == null) {
return Response.status(400).entity("Please provide all mandatory inputs").build();
}
user.setId(DB.values().size()+1);
user.setUri("/user-management/"+user.getId());
DB.put(user.getId(), user);
return Response.status(201).contentLocation(new URI(user.getUri())).build();
}
#GET
#Path("/{id}")
#Produces("application/json")
public Response getUserById(#PathParam("id") int id) throws URISyntaxException
{
User user = DB.get(id);
if(user == null) {
return Response.status(404).build();
}
return Response
.status(200)
.entity(user)
.contentLocation(new URI("/user-management/"+id)).build();
}
#PUT
#Path("/{id}")
#Consumes("application/json")
#Produces("application/json")
public Response updateUser(#PathParam("id") int id, User user) throws URISyntaxException
{
User temp = DB.get(id);
if(user == null) {
return Response.status(404).build();
}
temp.setFirstName(user.getFirstName());
temp.setLastName(user.getLastName());
DB.put(temp.getId(), temp);
return Response.status(200).entity(temp).build();
}
#DELETE
#Path("/{id}")
public Response deleteUser(#PathParam("id") int id) throws URISyntaxException {
User user = DB.get(id);
if(user != null) {
DB.remove(user.getId());
return Response.status(200).build();
}
return Response.status(404).build();
}
static
{
User user1 = new User();
user1.setId(1);
user1.setFirstName("John");
user1.setLastName("Wick");
user1.setUri("/user-management/1");
User user2 = new User();
user2.setId(2);
user2.setFirstName("Harry");
user2.setLastName("Potter");
user2.setUri("/user-management/2");
DB.put(user1.getId(), user1);
DB.put(user2.getId(), user2);
}
}
Users.java
package com.howtodoinjava.jerseydemo;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#XmlAttribute(name = "id")
private int id;
#XmlAttribute(name="uri")
private String uri;
#XmlElement(name = "firstName")
private String firstName;
#XmlElement(name = "lastName")
private String lastName;
// Getters and Setters
}
Configure Jersey
Now we have a JAX-RS resource and we want to access it from spring boot application which include Jersey dependency. Let’s register this resource as Jersey resource.
package com.howtodoinjava.jerseydemo;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;
#Component
public class JerseyConfig extends ResourceConfig
{
public JerseyConfig()
{
register(SecurityFilter.class);
register(UserResource.class);
}
}
Look at the #Component annotation. It enables this class to be
registered while spring boot auto scans the java classes in source
folder.
ResourceConfig provides advanced capabilities to simplify
registration of JAX-RS components.
SecurityFilter class is the actual auth details processor which we
will see later in this tutorial.
Extend spring boot application with SpringBootServletInitializer.
package com.howtodoinjava.jerseydemo;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
#SpringBootApplication
public class JerseydemoApplication extends SpringBootServletInitializer
{
public static void main(String[] args)
{
new JerseydemoApplication().configure(new SpringApplicationBuilder(JerseydemoApplication.class)).run(args);
}
}
Secure REST APIs with JAX-RS Annotations
Now when our APIs are ready, we will start securing them. Let’s annotate the APIs with JAX-RS annotations based on their desired access level and user roles allowed to access them.
package com.howtodoinjava.jerseydemo;
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "users")
#Path("/users")
public class UserResource
{
private static Map<Integer, User> DB = new HashMap<>();
#GET
#PermitAll
#Produces("application/json")
public Users getAllUsers() {
Users users = new Users();
users.setUsers(new ArrayList<>(DB.values()));
return users;
}
#POST
#Consumes("application/json")
#RolesAllowed("ADMIN")
public Response createUser(User user) throws URISyntaxException
{
if(user.getFirstName() == null || user.getLastName() == null) {
return Response.status(400).entity("Please provide all mandatory inputs").build();
}
user.setId(DB.values().size()+1);
user.setUri("/user-management/"+user.getId());
DB.put(user.getId(), user);
return Response.status(201).contentLocation(new URI(user.getUri())).build();
}
#GET
#Path("/{id}")
#Produces("application/json")
#PermitAll
public Response getUserById(#PathParam("id") int id) throws URISyntaxException
{
User user = DB.get(id);
if(user == null) {
return Response.status(404).build();
}
return Response
.status(200)
.entity(user)
.contentLocation(new URI("/user-management/"+id)).build();
}
#PUT
#Path("/{id}")
#Consumes("application/json")
#Produces("application/json")
#RolesAllowed("ADMIN")
public Response updateUser(#PathParam("id") int id, User user) throws URISyntaxException
{
User temp = DB.get(id);
if(user == null) {
return Response.status(404).build();
}
temp.setFirstName(user.getFirstName());
temp.setLastName(user.getLastName());
DB.put(temp.getId(), temp);
return Response.status(200).entity(temp).build();
}
#DELETE
#Path("/{id}")
#RolesAllowed("ADMIN")
public Response deleteUser(#PathParam("id") int id) throws URISyntaxException {
User user = DB.get(id);
if(user != null) {
DB.remove(user.getId());
return Response.status(200).build();
}
return Response.status(404).build();
}
static
{
User user1 = new User();
user1.setId(1);
user1.setFirstName("John");
user1.setLastName("Wick");
user1.setUri("/user-management/1");
User user2 = new User();
user2.setId(2);
user2.setFirstName("Harry");
user2.setLastName("Potter");
user2.setUri("/user-management/2");
DB.put(user1.getId(), user1);
DB.put(user2.getId(), user2);
}
}
You can see the security related JAX-RS annotations in above
highlighted lines.
Write security filter using JAX-RS ContainerRequestFilter
Now it’s time to write our security filter which will examine the incoming requests, fetch the authorization information (basic auth in this example), and then will match user name and password, and finally it will verify the user’s access level by it’s role. If everything matches, API will be accessed else user will get access denied response.
package com.howtodoinjava.jerseydemo;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
/**
* This filter verify the access permissions for a user based on
* user name and password provided in request
* */
#Provider
public class SecurityFilter implements javax.ws.rs.container.ContainerRequestFilter
{
private static final String AUTHORIZATION_PROPERTY = "Authorization";
private static final String AUTHENTICATION_SCHEME = "Basic";
private static final Response ACCESS_DENIED = Response.status(Response.Status.UNAUTHORIZED).build();
private static final Response ACCESS_FORBIDDEN = Response.status(Response.Status.FORBIDDEN).build();
private static final Response SERVER_ERROR = Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
#Context
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext requestContext)
{
Method method = resourceInfo.getResourceMethod();
//Access allowed for all
if( ! method.isAnnotationPresent(PermitAll.class))
{
//Access denied for all
if(method.isAnnotationPresent(DenyAll.class))
{
requestContext.abortWith(ACCESS_FORBIDDEN);
return;
}
//Get request headers
final MultivaluedMap<String, String> headers = requestContext.getHeaders();
//Fetch authorization header
final List<String> authorization = headers.get(AUTHORIZATION_PROPERTY);
//If no authorization information present; block access
if(authorization == null || authorization.isEmpty())
{
requestContext.abortWith(ACCESS_DENIED);
return;
}
//Get encoded username and password
final String encodedUserPassword = authorization.get(0).replaceFirst(AUTHENTICATION_SCHEME + " ", "");
//Decode username and password
String usernameAndPassword = null;
try {
usernameAndPassword = new String(Base64.getDecoder().decode(encodedUserPassword));
} catch (Exception e) {
requestContext.abortWith(SERVER_ERROR);
return;
}
//Split username and password tokens
final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");
final String username = tokenizer.nextToken();
final String password = tokenizer.nextToken();
//Verifying Username and password
if(!(username.equalsIgnoreCase("admin") && password.equalsIgnoreCase("password"))){
requestContext.abortWith(ACCESS_DENIED);
return;
}
//Verify user access
if(method.isAnnotationPresent(RolesAllowed.class))
{
RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
Set<String> rolesSet = new HashSet<String>(Arrays.asList(rolesAnnotation.value()));
//Is user valid?
if( ! isUserAllowed(username, password, rolesSet))
{
requestContext.abortWith(ACCESS_DENIED);
return;
}
}
}
}
private boolean isUserAllowed(final String username, final String password, final Set<String> rolesSet)
{
boolean isAllowed = false;
//Step 1. Fetch password from database and match with password in argument
//If both match then get the defined role for user from database and continue; else return isAllowed [false]
//Access the database and do this part yourself
//String userRole = userMgr.getUserRole(username);
String userRole = "ADMIN";
//Step 2. Verify user role
if(rolesSet.contains(userRole))
{
isAllowed = true;
}
return isAllowed;
}
}

Related

Making attribute in json request object not null

I'm building a Spring application which has #RestController, like:
#RestController
#RequestMapping(value = "/master")
public class MyController {
#Autowired
private MyService service;
#PostMapping("/call")
public ResponseEntity<Boolean> apiCall(#RequestBody MyDTO myDto) { ;
return new ResponseEntity<Boolean>(service.apiCall(myDto), OK);
}
}
And a request object:
public class MyDTO {
#JsonProperty("emp_number")
private long empNumber;
#JsonProperty("office_id")
private long officeId;
// ....constructors, etc.
}
In request json I want officeId to be not null.
So far I've tried marking the officeId field as:
#com.fasterxml.jackson.databind.annotation.JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
#JsonProperty(required = true)
#javax.validation.constraints.NotNull
But in the request json, even if I miss office_id, it is not throwing any error.
What am I missing?
It could be that in your case you are deserializing request, and missing primitive properties which are referenced by constructor are assigned a default value
java defaults
You could try to use corresponding Long wrapper object for MyDTO instead of primitives or maybe deserialization feature FAIL_ON_NULL_FOR_PRIMITIVES
You have to change the type from primitive to wrapper otherwise the default value of 0 will be considered and validation will pass.
Annotate MyDTO with #Valid annotation.
When Spring Boot finds an argument annotated with #Valid, it automatically bootstraps the default JSR 380 implementation — Hibernate Validator — and validates the argument.
from here
Please add following dependency to pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
PS: i have made minor adjustments to response structure to see the error in response
Entire code is as follows:
package com.example.spring.java.springjavasamples;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.Map;
#SpringBootApplication
public class SpringJavaSamplesApplication {
public static void main(String[] args) {
SpringApplication.run(SpringJavaSamplesApplication.class, args);
}
}
#RestController
#RequestMapping(value = "/master")
class MyController {
private final MyService service;
public MyController(MyService service) {
this.service = service;
}
#PostMapping("/call")
public ResponseEntity<Map<String, Object>> apiCall(#Valid #RequestBody MyDTO myDto, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
Map<String, String> errors = new HashMap<>();
bindingResult.getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return prepareResponse("error", errors, HttpStatus.BAD_REQUEST);
} else {
return prepareResponse("data", service.apiCall(myDto), HttpStatus.OK);
}
}
private ResponseEntity<Map<String, Object>> prepareResponse(String key, Object data, HttpStatus status) {
Map<String, Object> map = new HashMap<>();
map.put(key, data);
return new ResponseEntity<>(map, status);
}
}
class MyDTO {
#NotNull(message = "Employee number cannot be null")
#JsonProperty("emp_number")
private Long empNumber;
#NotNull(message = "Office Id cannot be null")
#JsonProperty("office_id")
private Long officeId;
#Override
public String toString() {
return "MyDTO{" +
"empNumber=" + empNumber +
", officeId=" + officeId +
'}';
}
}
#Service
class MyService {
public String apiCall(MyDTO myDto) {
System.out.println("all valid: " + myDto);
return myDto.toString();
}
}

When using Quarkus rest data Panache how to access username from request header in #PrePersist

I am trying to log the user that modified the entity. The reverse proxy is setting the user name in the request header.
How can the request and headers be read from an independent class when rest Panache is used to expose JAX-RS CRUD
below an example of what I tried but I am getting null or null pointer exep
package org.acme.manrest;
import javax.enterprise.context.RequestScoped;
import javax.persistence.PrePersist;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import org.acme.jpa.TBusiness;
import org.jboss.logging.Logger;
#RequestScoped
public class HeaderValue {
private static final Logger LOG = Logger.getLogger(HeaderValue.class);
#Context
HttpServletRequest request;
public HttpServletRequest getRequest() {
return request;
}
#Context
HttpHeaders httpHeaders;
#HeaderParam("x-remote-user")
String userName;
public String getUserName() {
LOG.info("xxx: " + getRequest().getHeader("x-remote-user"));
LOG.info("userName: " + userName);
LOG.info("getUserName2: " + getUserName2());
LOG.info("getUserName3: " + getUserName3());
return userName;
}
public String getUserName2() {
return httpHeaders.getRequestHeader("x-remote-user").get(0);
}
public String getUserName3() {
LOG.info("getUserName from class " + request.getHeader("x-remote-user"));
return request.getHeader("x-remote-user");
}
#PrePersist
void onPrePersist(TBusiness myEntity) {
LOG.info("getUserName: " + userName);
myEntity.createdBy = userName;
myEntity.updatedBy = userName;
}
}
Could switching to JWT and using JWT RBAC in Quarkus be a workaround?
got this to work by adding undertow dependency :
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-undertow</artifactId>
</dependency>
then in an EntityListener class created below PrePersist method:
#RequestScoped
// #Path("api/v1/Header")
public class AuditingEntityListener {
private static final Logger LOG = Logger.getLogger(AuditingEntityListener.class);
// Inject the bean so that Quarkus does not remove it at build time (IMPORTANT)
#Inject
HttpServletRequest requestNotUsed;
#PrePersist
void onPrePersist(TBusiness myEntity) {
HttpServletRequest HSR = CDI.current().select(HttpServletRequest.class).get();
LOG.info("HSR getRequestHeader user: " + HSR.getHeader("x-remote-user"));
}
}
using JWT RBAC in Quarkus also works:
#PrePersist
void onPrePersist(TBusiness myEntity) {
JsonWebToken context = CDI.current().select(JsonWebToken.class).get();
LOG.info("context: " + context.getClaim("preferred_username"));
}

How to create CRUD soap client with the feign-soap library?

The following code is my soap web service with CRUD operations:
UserService.java
package com.gpcoder.ws;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
#WebService
#SOAPBinding(style = SOAPBinding.Style.RPC)
public interface UserService {
#WebMethod
int insert(User user);
#WebMethod
boolean update(User user);
#WebMethod
boolean delete(int id);
#WebMethod
User get(int id);
#WebMethod
User[] getAll();
}
UserServiceImpl.java
package com.gpcoder.ws;
import java.util.HashMap;
import java.util.Map;
import javax.jws.WebService;
#WebService(endpointInterface = "com.gpcoder.ws.UserService")
public class UserServiceImpl implements UserService {
private static final Map<Integer, User> USERS = new HashMap<>();
#Override
public int insert(User user) {
Integer id = generateUniqueId();
user.setId(id);
USERS.put(id, user);
return id;
}
private int generateUniqueId() {
return USERS.keySet().stream().max((x1, x2) -> x1 - x2).orElse(0) + 1;
}
#Override
public boolean update(User user) {
return USERS.put(user.getId(), user) != null;
}
#Override
public boolean delete(int id) {
return USERS.remove(id) != null;
}
#Override
public User get(int id) {
return USERS.getOrDefault(id, new User());
}
#Override
public User[] getAll() {
return USERS.values().toArray(new User[0]);
}
}
SoapPublisher.java
package com.gpcoder.ws;
import javax.xml.ws.Endpoint;
public class SoapPublisher {
public static final String WS_URL = "http://localhost:8080/ws/users";
public static void main(String[] args) {
Endpoint.publish(WS_URL, new UserServiceImpl());
System.out.println("Server is published!");
}
}
I would like to use the feign-soap library to call these soap API. I tried to implement it following the feign-soap document. Here is my client-side code:
pom.xml
<!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-soap -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-soap</artifactId>
<version>10.2.3</version>
</dependency>
UserService.java
import java.util.ArrayList;
import java.util.List;
import com.gpcoder.model.User;
import feign.Headers;
import feign.RequestLine;
#Headers({ "Content-Type: text/xml" })
public interface UserService {
#RequestLine("POST /get")
#Headers({ "SOAPAction: get" })
String getUser(int id);
#RequestLine("POST /insert")
#Headers({ "SOAPAction: insert" })
String createUser(User user);
#RequestLine("POST /update")
#Headers({ "SOAPAction: update" })
String updateUser(User user);
#RequestLine("POST /delete")
#Headers({ "SOAPAction: delete" })
String deleteUser(int id);
default List<String> getUsers(int... ids) {
List<String> orders = new ArrayList<>();
for (int id : ids) {
orders.add(this.getUser(id));
}
return orders;
}
}
FeignClientCreator.java
import feign.Feign;
import feign.jaxb.JAXBContextFactory;
import feign.soap.SOAPDecoder;
import feign.soap.SOAPEncoder;
import feign.soap.SOAPErrorDecoder;
public class FeignClientCreator {
public static final String BASE_URL = "http://localhost:8080/ws/users";
public static <T> T getService(Class<T> clazz) {
JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder()
.withMarshallerJAXBEncoding("UTF-8")
.withMarshallerSchemaLocation("http://apihost http://apihost/schema.xsd")
.build();
return Feign.builder()
.encoder(new SOAPEncoder(jaxbFactory))
.decoder(new SOAPDecoder(jaxbFactory))
.errorDecoder(new SOAPErrorDecoder())
.target(clazz, BASE_URL);
}
}
FeignClientExample.java
import java.io.IOException;
import com.gpcoder.helper.FeignClientCreator;
import com.gpcoder.model.User;
import com.gpcoder.service.UserService;
public class FeignClientExample {
private static UserService userService;
public static void main(String[] args) throws IOException {
userService = FeignClientCreator.getService(UserService.class);
createUser();
}
private static void createUser() throws IOException {
User user1 = new User();
user1.setId(1);
user1.setUsername("gpcoder.com");
System.out.println("createUser1: " + userService.createUser(user1));
}
}
I don't know where is my code wrong. When I run my program, it show error log:
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Cannot find dispatch method for {}user
at feign.soap.SOAPErrorDecoder.decode(SOAPErrorDecoder.java:68)
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:149)
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:78)
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103)
at com.sun.proxy.$Proxy3.createUser(Unknown Source)
at com.gpcoder.FeignClientExample.createUser(FeignClientExample.java:32)
at com.gpcoder.FeignClientExample.main(FeignClientExample.java:16)
Does anyone already worked with this library or have some documents about it please give me some information?

Java spring mvc using hibernate to do update

I started to develop APIs for iOS app using Java Spring MVC two months ago.
I'll explain my question with an example for clarification purpose.
Let's say I want to update a user's name.
My mySQL user table has columns: id, user_id, email, display_name.
My approach was:
define user:
User.java:
package bean;
public class User {
String displayName;
String email;
String userId;
getters/setters...
}
2.define a DAO:
UserDao.java:
package dao;
import bean.StandardResponse;
public interface UserDao {
public StandardResponse updateUserName(String user_id,String userName);
}
UserDaoImpl.java:
package implement;
import bean.User;
import common.DatabaseConnect;
public UserDaoImpl implements UserDao {
private DatabaseConnect dbConnect;
public UserDaoImpl(DatabaseConnect dbConnect) {
this.dbConnect = dbConnect;
}
public StandardResponse updateUserName(userId,userName) {
if ((userId == null || userId.isEmpty()) ||(userName == null || userName.isEmpty())) return new StandardResponse("Error","Parameters not set!");
String sql = null;
Statement smt = dbConnect.createDataBaseConnectResourse();
StandardResponse result = new StandardResponse("Error","Fail to update the record!");
sql = "update User set user_name="+userName+" where user_id='"+userId+"'";
int updateResult = 0;
try {
updateResult = smt.executeUpdate(sql);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
dbConnect.closeDatabaseConnectResource();
}
if (updateResult == 1) {
result = new StandardResponse("Success","The record has been updated!");
}
return result;
}
}
3.controller
import org.springframework.stereotype.Controller;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import bean.StandardResponse;
import bean.User;
import common.DatabaseConnect;
import common.SpringApplicationContext;
import dao.UserDao;
import implement.UserDAOImpl;
#Controller
#RestController
#RequestMapping("user")
public class UserController {
DatabaseConnect dbConnect = SpringApplicationContext.getApplicationContext().getBean("databaseConnect", DatabaseConnect.class);
UserDao uiObject = new UserDaoImpl(dbConnect);
#RequestMapping(value = "/updateUserName", method = RequestMethod.POST)
public StandardResponse updateUserName(HttpServletRequest request, HttpServletResponse reponses, Model model) {
StandardResponse srObject = uiObject.updateUserName(request.getparameter("userId"),request.getParameter("userName"));
return srObject;
}
}
I just put the crucial classes here. I believe you can understand what I am doing here. So if someone access the URL:****/user/updateUserName providing the userId and userName, he can update the user name of that record. It is functionalbe.
I used the same approach and finished the whole project. It is working. Then, I asked an experienced programmer to look at my code since I figured out all these based on my own understanding. I would like to know how did they do in industry. He gave me some valuable comments.
The whole structure is wrong. I shouldn't have logics in my dao. I should at least have dao, service and action layers. dao only handles database access, service handles all the logic and action handels communication and decide which service to call.
It is very bad approach to hand written SQL in the code. I should use Hibernate.
I should use control inverse and dependency injection.(I am not dealing with this in this post.)
So I started to update my codes to use Hibernate.
define user:
User.java:
package model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="User")
public class User {
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(name = "user_id")
private String userId;
#Column(name = "user_name")
private String displayName;
#Column(name = "email")
private String emai;
all getters/setters...
}
dao:
UserDao.java:
package dao;
import model.User;
import java.util.List;
public interface UserDAO {
public void updateUser(User p);
other methods....
}
UserDaoImpl.java
package dao;
import model.User;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Repository;
import model.User;
#Repository
public class PersonDAOImpl implements PersonDAO {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
this.sessionFactory = sf;
}
#Override
public void updatePerson(Person p) {
Session session = this.sessionFactory.getCurrentSession();
session.update(p);
}
implementations of other methods....
}
service:
UserService.java:
package service;
import java.util.List;
import model.User;
public interface UserService {
public void updateUser(User p);
other methods....
}
UserServiceImpl.java:
package service;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import dao.UserDAO;
import model.User;
#Service
public class UserServiceImpl implements UserService {
private UserDAO userDAO;
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
#Override
#Transactional
public void updateUser(User p) {
this.userDAO.updateUser(p);
}
implementation of other methods...
}
Now, I just need to write a class to handle the request and call this updateUser service. The whole structure looks better than mine. However, the request won't gave me the whole user object. All I can get is user_id and user_name. I am also not allowed to put logics in dao. So I have to query the table first to get the whole user object and then update the user_name. Comparing to what I used to do, one SQL handles the update. Now using Hibernate, I need 1 query and 1 update.
I found a solution on StackOverflow that I can use HQL to do this in one step. But I though the purpose for using Hibernate is to free us from writing the SQL. If I need to write HQL, why don't I just keep using the writing SQL approach.
So is there a way to do update with Hibernate without query the table first in this structure? Or this is a trade-off for better structure?
I am sorry that I used a really long example for this question. But I couldn't think of other ways to explain the whole story clearly.
So is there a way to do update with Hibernate without query the table first in this structure? Or this is a trade-off for better structure?
Thereis NO tradeoff, you can do updates with HQL(Hibernate Query Language) as well like how you do in SQL.
You can look at the following code:
UserDAOImpl class:
#Repository
//you are calling this in ur code as PersonDAOImpl..change it to UserDAOImpl
public class UserDAOImpl implements UserDAO {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
this.sessionFactory = sf;
}
#Override
public int updateUser(String userId, String userName) {
Session session = this.sessionFactory.getCurrentSession();
Query query = session.createQuery("update User set userName =:userName where userId = :userName ");
query.setString("userName", userName);
query.setString(userName, userName);
int result = query.executeUpdate();
return result;
}
}
UserServiceImpl class:
#Service
public class UserServiceImpl implements UserService {
private UserDAO userDAO;
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
#Override
#Transactional
public void updateUserName(String userId, String userName) {
if(userId !=null && userName != null) {
int result = this.userDAO.updateUser(userId, userName);
if(result==0) //userid not available {
//if userid is NOT available, what to do? check your requirement and handle properly
}
}
} else {
//throw exception
}
}
implementation of other methods...
}
Controller Class:
#Controller
#RestController
#RequestMapping("user")
public class UserController {
#Autowired
private UserService userService;
#RequestMapping(value = "/updateUserName", method = RequestMethod.POST)
public StandardResponse updateUserName(HttpServletRequest request, HttpServletResponse reponses, Model model) {
StandardResponse srObject = userService.updateUserName(request.getparameter("userId"),request.getParameter("userName"));
return srObject;
}
}

JAX-RS and CDI - Injecting stateful session bean : setter does not work

I am working on a webservice using RESTEasy.
I have an "authentication" webservice with two methods : "login" and "logout".
I have a stateful session scoped bean, UserData with two attributes : "loggedIn", boolean, and "userId", Integer.
I am injecting UserData in my Authentication class. It is working well for the "loggedIn" attribute, when I call "login" method, it is set to true and then it remains true until the session ends.
But strangely it is not working with "userId" attribute. When I call "login" method, I set userId to my user id but right after the "setUserId" method is called, userId is still null.
Here is Authentication class code (without logOut method, unused for now ) :
package com.bini.dev.dilemme.web.api;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import com.bini.dev.dilemme.business.service.UserService;
import com.bini.dev.dilemme.persistence.model.User;
import com.bini.dev.dilemme.web.UserData;
#Path("/auth")
public class AuthenticationApi {
#Inject
private UserData userData;
#Inject
private UserService userService;
#GET
#Path("login")
#Produces("application/json")
public UserData logIn(#QueryParam("mail") String userMail, #QueryParam("password") String userHashedPassword) {
try {
this.logOut();
User user = userService.getUserByMailAddress(userMail.trim());
if (user == null)
throw new Exception("User does not exists");
boolean loggedIn = userService.checkUserPassword(user, userHashedPassword.trim());
if (loggedIn) {
userData.setLoggedIn(true);
userData.setUserId(user.getUserId());
}
return userData;
} catch (Exception e) {
e.printStackTrace();
return userData;
}
}
}
And here is the code of "UserData" class :
package com.bini.dev.dilemme.web;
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
#SessionScoped
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.PROTECTED_AND_PUBLIC,
getterVisibility = JsonAutoDetect.Visibility.NONE,
setterVisibility = JsonAutoDetect.Visibility.NONE)
public class UserData implements Serializable {
protected Boolean loggedIn;
protected Integer userId;
public UserData() {
this.loggedIn = false;
this.userId = null;
}
public Boolean isLoggedIn() {
return loggedIn;
}
public void setLoggedIn(Boolean loggedIn) {
this.loggedIn = loggedIn;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
}
I tried with or without "Stateful" and "Stateless" annotation. Doesn't change anything.
I really have not idea what to do.
I thought it might be a "setter" syntax error, but I really don't see where.
EDIT : BTW, I am using Weld and RestEASY with WildFly server.
Thanks :)

Categories

Resources