Spring RestController RequestMapping add Variable - spring-boot

How can I add the Variable "userId" to the Json-String?
#RestController
#RequestMapping("/api/chats")
public class ChatRestController {
#JsonView(ChatViews.showCurrentUserChat.class)
#GetMapping("/myStudentChats/{id}")
public Chat getChat(#AuthenticationPrincipal User user, #PathVariable Long id) {
Int userId = user.getId()
return user.getStudentChat(id).orElse(null);
}
}

Related

cacheManager.getCache always return null but the value is in cacheManager bean when inspect the object

I'm trying to use Spring Cache to store data, generated by another method inside Service class.
This method marked with #Cacheable is a public method, the cache is being called in Controller layer.
When I do debugging, I inspect the object cacheManager, I found that it contains the map that I stored, but when calling the method cacheManager.getCache("cache") it return null.
Question is why that method return null while the object is holding the value?
This is the config, service and controller:
Spring bean config:
#EnableCaching
public class CachingConfig {
#Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("optCache");
}
}
Service:
public void verify(Request request, String authorization) {
String memberId = parseAuthToken(authorization).getMembershipID();
buildOtpCache(memberId, request.getTokenUUID(), 0)
}
#Cacheable("otpCache")
public OTPCache buildOtpCache(String memberId, String uuid, int counter) {
return OTPCache.builder()
.memberId(memberId)
.tokenUUID(uuid)
.timestamp(LocalDateTime.now())
.counter(counter)
.build();
}
Controller:
#Override
public void verifyOTP(MeOTPVerifyRequest verifyOTPRequest, String authorization) {
String memberId = parseAuthToken(authorization).getMembershipID();
Collection<String> a = cacheManager.getCacheNames();
OTPCache OTPCache = cacheManager.getCache("cache").get(memberId, OTPCache.class);
otpService.verify(verifyOTPRequest, authorization);
}
EDIT:
This is my new service class, remove #Cacheable annotation:
public void verify(Request request, String authorization) {
String memberId = parseAuthToken(authorization).getMembershipID();
cacheManager.getCache("optCache").put(memberId, buildOtpCache(memberId, request.getTokenUUID(), 0));
}
public OTPCache buildOtpCache(String memberId, String uuid, int counter) {
return OTPCache.builder()
.memberId(memberId)
.tokenUUID(uuid)
.timestamp(LocalDateTime.now())
.counter(counter)
.build();
}

Strategy pattern in Spring boot application for payment gateway and methods

I have a controller where I am being passed a gatewayid for different providers. I have a BasePaymentService interface which is implemented by Payu service and Razorpay service for now.
I want to avoid using if condition for and have the strategy added without changing code and have the container inject correct strategy.
How do I add a strategy pattern here?
Would callback method be also a part of strategy here?
How do I account for different payment methods here? (cards, wallets)
BasePaymentService
public interface BasePaymentService {
PaymentDetail makePayment(PaymentDetail detail);
Payment callbackPayment(PaymentCallback detail);
}
Concrete PaymentService
#Service
#Slf4j
public class PayuPaymentService implements BasePaymentService {
#Autowired
PaymentRepository paymentRepository;
public PaymentDetail makePayment(PaymentDetail paymentDetail) {
PaymentUtil paymentUtil = new PaymentUtil();
paymentDetail = paymentUtil.populatePaymentDetail(paymentDetail);
savePaymentDetail(paymentDetail);
return paymentDetail;
}
#Override
public Payment callbackPayment(PaymentCallback paymentResponse) {
log.info("inside callback service >>>>>");
String msg = "Transaction failed.";
Payment payment = paymentRepository.findByTxnId(paymentResponse.getTxnid());
if(payment != null) {
log.info("in condition callback service");
//TODO validate the hash
PaymentStatus paymentStatus = null;
if(paymentResponse.getStatus().equals("failure")){
paymentStatus = PaymentStatus.Failed;
}else if(paymentResponse.getStatus().equals("success")) {
paymentStatus = PaymentStatus.Success;
msg = "Transaction success";
}
payment.setPaymentStatus(paymentStatus);
payment.setMihpayId(paymentResponse.getMihpayid());
payment.setMode(paymentResponse.getMode());
paymentRepository.save(payment);
}
return payment;
}
private void savePaymentDetail(PaymentDetail paymentDetail) {
log.info("in proceedPayment save");
Payment payment = new Payment();
payment.setAmount(Double.parseDouble(paymentDetail.getAmount()));
payment.setEmail(paymentDetail.getEmail());
payment.setName(paymentDetail.getName());
payment.setPaymentDate(new Date());
payment.setPaymentStatus(PaymentStatus.Pending);
payment.setPhone(paymentDetail.getPhone());
payment.setProductInfo(paymentDetail.getProductInfo());
payment.setTxnId(paymentDetail.getTxnId());
paymentRepository.save(payment);
}
}
Controller
#Api(value = "swipe: payment Service", tags = "Example")
#Validated
#RestController
#Slf4j
#RequestMapping(value = CommonConstants.BASE_CONTEXT_PATH)
public class CommonController {
#Autowired
private BasePaymentService paymentService;
#CrossOrigin(origins = "*")
#PostMapping(path = "/payment-details")
public #ResponseBody
PaymentDetail proceedPayment(#RequestBody PaymentDetail paymentDetail){
if(paymentDetail.getGatewayId().equalsIgnoreCase("payu") ){
paymentService.makePayment(paymentDetail);
}
else if(paymentDetail.getGatewayId().equalsIgnoreCase("rp")){
paymentService.makePayment(paymentDetail);
}
return paymentDetail;
}
#CrossOrigin(origins = "*" )
#RequestMapping(path = "/payment-response", method = RequestMethod.POST)
public #ResponseBody
Payment payuCallback(#RequestParam String mihpayid, #RequestParam String status, #RequestParam PaymentMode mode, #RequestParam String txnid, #RequestParam String hash, #RequestParam String amount, #RequestParam String productinfo, #RequestParam String firstname, #RequestParam String lastname, #RequestParam String email, #RequestParam String phone, #RequestParam String error, #RequestParam String bankcode, #RequestParam String PG_TYPE, #RequestParam String bank_ref_num, #RequestParam String unmappedstatus){
log.info("inside callback");
PaymentCallback paymentCallback = new PaymentCallback();
paymentCallback.setMihpayid(mihpayid);
paymentCallback.setTxnid(txnid);
paymentCallback.setMode(mode);
paymentCallback.setHash(hash);
paymentCallback.setStatus(status);
return paymentService.callbackPayment(paymentCallback);
}
}

How to get query Params from URL along with generics and not as String for GET request in spring boot

I wanted to read the parameters with the same data type and not as string from my GET request. I am actually getting the entire Request params as String. Need to know if there is way to read the params with their specified data types
Yes. Please refer below examples of GET and POST both which suits your problem.
Suppose your Json is:
{
"name" : "john"
"age" : 30
}
Your mapping class is
public class user {
private String name;
private Long age;
//getter & setter
}
Your controller class will be :
#RestController
#RequestMapping("/user")
public class UserController {
#PostMapping("/add")
public void addUser(#RequestBody User user) {
System.print.out(user.getName());
}
// URL will be http://localhost:8080/user?userId=
#GetMapping
public void getUser(#RequestParam Long userId) {
}
// URL will be http://localhost:8080/user/1
// likewise you can specify multiple path variable in URL separated by "/"
#GetMapping
public void getUser(#PathVariable("id") long id) {
}

Spring boot - To execute statement sql update (JPA)

I just have started with Spring Boot and I am practicing in base to this example:
http://www.devglan.com/spring-boot/spring-boot-angular-example
The physical deleted is working ok, but I am trying to do a logical deleted and I do not know how to do it.
This is my classes:
UserController
#DeleteMapping(path ={"logical/{id}"})
public User deleteLogical(#PathVariable("id") int id, #RequestBody User user) {
return userService.deleteLogical(id, user);
}
UserService
User deleteLogical(int id, User user);
UserServiceImpl
#Override
// #Query("update user set remove = false where id = ?1")
public User deleteLogical(int id, User user) {
// user.setRemove(false);
return repository.save(user);
}
UserRepository
User save(User user);
This is the SQL statement I want to execute:
UPDATE user SET remove = false WHERE id =?;
How I could do it? Thanks,
I think you dont need to pass User object. Id will be enough.
So your code will be changed
#DeleteMapping(path ={"logical/{id}"})
public User deleteLogical(#PathVariable("id") int id) {
return userService.deleteLogical(id, user);
}
UserService
User deleteLogical(int id);
UserServiceImpl
#Override
public User deleteLogical(int id) {
User user = repository.findById(id);
user.setRemove(true);
return repository.save(user);
}
That's all.
You try to implement "soft delete" so you can try this approach:
User entity:
#Entity
User {
#Id
#GeneratedValue
private Integer id;
//...
private boolean removed; // user is removed if this property is true
//...
}
User service:
public interface UserService {
Optional<Integer> softDelete(int id);
}
#Service
public UserServiceImpl implements UserService (
// Injecting UserRepo
// First variant - read the user, set it removed, then updated it.
#Transactional
Optional<Integer> softDelete1(int id) {
// Using method findById from Spring Boot 2+, for SB1.5+ - use method findOne
return userRepo.findById(id).map(user -> {
user.setRemoved(true);
userRepo.save(user);
return 1;
});
}
// Second variant - update the user directly
#Transactional
Optional<Integer> softDelete2(int id) {
return userRepo.softDelete(id);
}
}
User controller:
#RestController
#RequestMapping("/users")
public class UserController {
// Injecting UserService
#DeleteMapping("/{id}")
public ResponseEntity<?> softDelete(#PathVariable("id") int id) {
return userService.softDelete1(id) // you can use 1 or 2 variants
.map(i -> ResponseEntity.noContent().build()) // on success
.orElse(ResponseEntity.notFound().build()); // if user not found
}
}
User repo:
public interface UserRepo extends JpaRepository<User, Integer>() {
#Modifying(clearAutomatically = true)
#Query("update User u set u.removed = true where u.id = ?1")
int remove(int id);
default Optional<Integer> softDelete(int id) {
return (remove(id) > 0) ? Optional.of(1) : Optional.empty();
}
}
UPDATED
Or, I think, you can just try to simply override the deleteById method of CrudRepository (not tested - please give a feedback):
#Override
#Modifying(clearAutomatically = true)
#Query("update User u set u.removed = true where u.id = ?1")
void deleteById(Integer id);
then use it in your service.

Spring MVC multiple form backing object

Say, in request, I'm getting
?name=Jack&age=26&price=100&quantity=2
I have two model objects as below
public class User {
public String name;
public String age;
//getters and setters
}
public class Order {
public int price;
public int quantity;
//getters and setters
}
Now I want to have a controller method as below
#RequestMapping(value = "/submit", method = RequestMethod.GET)
public String home(#ModelAttribute("user") User user, #ModelAttribute("order") Order order, Model model) {
//stuff
}
As you can see I want to populate the model objects using two separate #ModelAttribute annotation. Is this possible in spring mvc?
Sattyaki, I suggest you to provide a few getters/setters to User and Order, and then compose the desired request with another class:
public class Checkout {
private User user;
private Order order;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}
And to request for this operation, just issue a GET to the wanted URI(/submit) with your parameters. Observe that they are now using dot notation:
/submit?user.name=Jack&user.age=26&order.price=100&order.quantity=2

Resources