In a spring test they ask,
which can be the return type of a jdbcTemplate query.
Option were, with 3x to choose:
JSONObject
Generic Map
Domain Object
String
Im pretty sure with String and Domain Object, but what is the third?
It returns Generic Type, pretty much all.
#Override
public <T> T queryForObject(String sql, #Nullable Object[] args, Class<T> requiredType) throws DataAccessException {
return queryForObject(sql, args, getSingleColumnRowMapper(requiredType));
}
Map<String, Object>
#Override
public Map<String, Object> queryForMap(String sql, Object[] args, int[] argTypes) throws DataAccessException {
return result(queryForObject(sql, args, argTypes, getColumnMapRowMapper()));
}
Related
I am new to spring java. I have a controller class and repository class. what I actually want is to insert a json data into postgresql database by calling a database function(stored procedure)and return a json data as response.It shows that BAD SQL Grammar Error. Please help me to solve the issue...I am sharing my code. I am getting error in the
Map<String, Object> result =insertSurveyCall.execute(params); line.
UserController.java
#RequestMapping(value="/savedbData", method = RequestMethod.POST, produces="application/json;charset=utf-8")
public String uploadFile(#RequestParam String data,HttpServletRequest request, HttpServletResponse response) throws SQLException
{
JSONObject requestJSON= new JSONObject(data);
String result="";
result=userRepository.saveDatahouse(requestJSON);
return result.toString();
}
UserRepository.java
public interface UserRepository {
String saveDatahouse( JSONObject requestJSON) throws SQLException;
}
UserRepositoryImpl.java
#Override
public String saveDatahouse(JSONObject requestJSON) throws SQLException {
JSONObject dbdata = requestJSON;
JSONObject resultJSON = new JSONObject();
Map<String, Object> params = new HashMap<String, Object>();
String reult="";
try {
PGobject pObj = new PGobject();
pObj.setType("json");
pObj.setValue(dbdata.toString());
SimpleJdbcCall insertSurveyCall = new SimpleJdbcCall(jdbcTemplate).withFunctionName("add_data_to_db");
params.put("params", pObj);
Map<String, Object> result =insertSurveyCall.execute(params);
System.out.println("result at repository::::::::::::::::::::::::");
return resultJSON.toString();
} catch (IncorrectResultSizeDataAccessException e) {
return null;
}
}
I want to use continuously annotations with ArgumentResolver in the controller.
But ArgumentResolver is always returning objects.
What I want is AdminUserArgumentResolver to be an ArgumentResolver that verifies whether it is a manager.
LoginUserArgumentResolver wants to do a logic of finding members through tokens.
Two annotations are returning the Object. There seems to be a problem here.
Couldn't we, like #Valid Annotation, put up a series of annotations about Argument?
For example, public method(#Valid #RequestBody RequestDto requestDto)
// AdminUserArgumentResolver.class
#Component
public class AdminUserArgumentResolver implements HandlerMethodArgumentResolver {
#Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(AdminUser.class);
}
#Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
String role = (String)webRequest.getAttribute("role", SCOPE_REQUEST);
if (!Objects.equals(role, Role.ADMIN.name())) {
throw new InvalidAuthorizationException();
}
return null;
}
}
// LoginUserArgumentResolver.class
#Component
#RequiredArgsConstructor
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {
private final UserService userService;
#Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(LoginUser.class);
}
#Override
public User resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
String userId = (String)webRequest.getAttribute("userId", SCOPE_REQUEST);
if (StringUtils.isEmpty(userId)) {
throw new IllegalArgumentException();
}
try {
return userService.findById(Long.parseLong(userId));
} catch (Exception e) {
throw new UserNotFoundException();
}
}
}
//controller
#PostMapping
public ResponseEntity<Void> save(
#AdminUser #LoginUser User user, // I want to do this.
#Valid #RequestBody NoticeCreateRequest request
) {
Long noticeId = noticeService.save(request);
return ResponseEntity
.created(URI.create(String.format("/api/notices/%d", noticeId)))
.build();
}
I want to know the keywords related to it. Thank you.
I am using Spring's AbstractHttpMessageConverter to allow me instantiate my own object.
Converter
public class PaypalIPNHttpMessageConverter extends AbstractHttpMessageConverter<IPNMessage> {
public PaypalIPNHttpMessageConverter() {
super(MediaType.APPLICATION_FORM_URLENCODED, MediaType.TEXT_PLAIN);
}
#Override
protected boolean supports(Class<?> clazz) {
return clazz == IPNMessage.class;
}
#Override
protected IPNMessage readInternal(Class<? extends IPNMessage> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
//Converts HTTPRequest into map<string,string> that IPNMessage can then parse
String requestString = IOUtils.toString(inputMessage.getBody(), "UTF-8");
Map<String, String[]> requestMap = new LinkedHashMap<>();
for (String keyValue : requestString.split("&")) { //each key value is delimited by &
String[] pairs = keyValue.split("=", 2); // = pairs a key to a value
requestMap.put(pairs[0], pairs[1].split(",")); // , splits multiple values for that key
}
return new IPNMessage(requestMap);
}
#Override
protected void writeInternal(IPNMessage ipnMessage, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
}
}
In readINternal(), I am passed a HttpInputMessage object, which only has getBody() function that produces an InputStream of the HTTPRequest.
I have tried to write my own code to parse and build a ParameterMap but it does not always work if the urlencoding is different.
Is there anyway I can get Spring's WebRequest or HttpServletRequest object from the converter and use there wonderful getParameterMap() function?
TL;DR
Is there anyway to use WebRequest or HTTPServletRequest in the MessageConverter instead of HttpInput so I can use the wonderful getParameterMap() function, instead of reinventing the wheel?
Thanks
Look at how it is implemented in Spring FormHttpMessageConverter. It tokenizes request parameter using & just like your solution. However it dtermines the charset to use from the Content-Type request header if provided. Otherwise it uses default UTF-8
//extract from FormHttpMessageConverter
public MultiValueMap<String, String> read(Class<? extends MultiValueMap<String, ?>> clazz,
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
MediaType contentType = inputMessage.getHeaders().getContentType();
Charset charset = (contentType.getCharSet() != null ? contentType.getCharSet() : this.charset);
String body = StreamUtils.copyToString(inputMessage.getBody(), charset);
String[] pairs = StringUtils.tokenizeToStringArray(body, "&");
MultiValueMap<String, String> result = new LinkedMultiValueMap<String, String>(pairs.length);
for (String pair : pairs) {
int idx = pair.indexOf('=');
if (idx == -1) {
result.add(URLDecoder.decode(pair, charset.name()), null);
}
else {
String name = URLDecoder.decode(pair.substring(0, idx), charset.name());
String value = URLDecoder.decode(pair.substring(idx + 1), charset.name());
result.add(name, value);
}
}
return result;
}
You can simply get the current request using the following code
HttpServletRequest httpRequest = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
Custom permission evaluator
#Component
public class EventWritePermissionEvaluator implements PermissionEvaluator{
#Override
public boolean hasPermission(Authentication authentication,
Object targetDomainObject, Object permission) {
return true;
}
#Override
public boolean hasPermission(Authentication authentication,
Serializable targetId, String targetType, Object permission) {
return true;
}
}
#PreAuthorize("hasPermission(#event,'write')")
#RequestMapping(value="/events/{id}/start")
#ResponseBody
public Map<String, Object> eventStart(#RequestBody Event event, #PathVariable("id") int id, HttpServletRequest request, HttpServletResponse response) throws MessagingException
{
event.setId(id);
return eventService.eventStart(event, request, response);
}
In the above example i am sending event object to permission evaluator placing a "#" before it. Why "#"? How do i send just id instead of object?
For you it would look something like:
#PreAuthorize("hasPermission(#id, 'com.company.product.Event', 'read')")
#RequestMapping(value="/events/{id}")
#ResponseBody
public Event getEvent(#PathVariable("id") int id)
{
// get Event from dao
}
Note the extra parameter for hasPermission, that should be the name of your domain model class (can be custom if you implement PermissionEvaluator yourself).
Does anyone know how to change the posted values with a spring mvc interceptor ? I have seen some examples but none about this subject. I know how to get them but i don't know how to modify them.
#Component
public class CultureInterceptor implements HandlerInterceptor {
#Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
}
#Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
// we get the posted values
String culture = request.getParameter("culture");
String a = request.getParameter("a");
String b = request.getParameter("b");
System.out.println(String.format("[CultureInterceptor culture=%s, a=%s, b=%s]", culture, a, b));
if (culture != null && a != null && b != null && "fr-FR".equals(culture)) {
a = a.replace(",", ".");
b = b.replace(",", ".");
}
System.out.println(String.format("[CultureInterceptor culture=%s, a=%s, b=%s]", culture, a, b));
return true;
}
Above, I have created a copy of posted values [a] and [b] but i haven't modified them in the request. Any idea to do that ?
I answer my own question. In fact it is rather complex and it took me some time to find a working solution.
First, I created a filter in a Spring configuration class (Spring Boot environment exactly) :
#Configuration
#ComponentScan({ "istia.st.springmvc.config", "istia.st.springmvc.controllers", "istia.st.springmvc.models" })
#EnableAutoConfiguration
public class Config extends WebMvcConfigurerAdapter {
#Bean
public Filter cultureFilter() {
return new CultureFilter();
}
}
Here we declare a filter that will (by default) filter every request before it attains the final handler. Then I created the filter :
public class CultureFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// next handler
filterChain.doFilter(new CultureRequestWrapper(request), response);
}
}
[OncePerRequestFilter] is a Spring class. The trick is to replace the actual request with a new one [CultureRequestWrapper(request)]. Then I created the CultureRequestWrapper :
public class CultureRequestWrapper extends HttpServletRequestWrapper {
public CultureRequestWrapper(HttpServletRequest request) {
super(request);
}
#Override
public String[] getParameterValues(String name) {
// posted values a et b
if (name != null && (name.equals("a") || name.equals("b"))) {
String[] values = super.getParameterValues(name);
String[] newValues = values.clone();
newValues[0] = newValues[0].replace(",", ".");
return newValues;
}
// other cases
return super.getParameterValues(name);
}
}
I redefined the [getParameterValues] of [HttpServletRequest] but it depends on the final servlet that will manage the request. We have to redefine the
[HttpServletRequest] methods used by this servlet.
You shouldn't be changing anything in the HttpServletRequest as it should represent the request as it came from the client. The construct that is used for scenarios such as yours, is HttpServletRequestWrapper.
What you should do is extend the HttpServletRequestWrapper, override the getParameter method where you can apply your param change logic, and forward your wrapped request further down the forwarding chain.
This link can be of help to you, note that I don't think that this will work in an interceptor, and a filter is a right place to handle it, but you might try
If what you want is modify one modelAttribute that you render in the modelAndAttribute you can use his own annotation.
#ModelAttribute("here you put your entity name")
public Entity bindModel(final HttpServletRequest request) throws CandidacyException {
String foo = request.getParameter("foo");
foo = foo.concat("add new data");
Entity entity = new Entity();
entity.setFoo(foo);
return entity;
}