Jake Miller
Jake Miller

Reputation: 2652

Why is this AngularJS call causing a 400 bad request error (Spring back end)

This request below is causing a 400 bad request response:

$scope.addGiveaway = function(campaignId){
        var photo = $scope.photo;
        var giveaway = $scope.giveaway;
        var data = new FormData();
        data.append('photo', photo);
        data.append('giveaway', giveaway);
        var uploadUrl = "/dashboard/campaigns/"+campaignId+"/giveaways";
        $http.put(uploadUrl, data, {
            transformRequest: angular.identity,
            headers: {
                'Content-Type': 'multipart/form-data',
            }
        });

Here's the Spring controller:

    @RequestMapping(method = RequestMethod.PUT)
    public ResponseEntity<String> addGiveaway(@RequestParam("giveaway") Giveaway giveaway, 
                                              @RequestParam("photo") MultipartFile photo,
                                              @PathVariable("campaignId") long campaignId,
                                              Principal principal) throws Exception {

I have a @RequestMapping at the top of the entire controller class:

@RequestMapping("/dashboard/campaigns/{campaignId}/giveaways")

I've tried:

Why is this causing a 400 bad request response?

EDIT Posting entire controller class as requested. It shouldn't matter though as the logger at the top of the controller is not being called. It's not getting into the code of the controller.

@RestController
@RequestMapping("/dashboard/campaigns/{campaignId}/giveaways")
public class GiveawayController {

    @Autowired
    private GiveawayService giveawayService;

    @Autowired
    private CampaignService campaignService;

    @Autowired
    private BusinessUserService businessUserService;

    private static final Logger logger = Logger.getLogger(GiveawayController.class);

    /**
     * Uploads a giveaway to the server given data and a photo.
     * 
     * @param giveaway giveaway data to save
     * @param photo photo of the giveaway item
     * @param principal authenticated user
     * @return status code and errors
     * @throws Exception
     */
    @RequestMapping(method = RequestMethod.PUT)
    public ResponseEntity<String> addGiveaway(@RequestParam("giveaway") Giveaway giveaway, 
                                              @RequestParam("photo") MultipartFile photo,
                                              @PathVariable("campaignId") long campaignId,
                                              Principal principal) throws Exception {
        logger.info("Made it into the controller");

        Campaign campaign = campaignService.findOne(campaignId);
        campaignService.verifyCampaignOwnership(
                            businessUserService
                                .findByEmail(principal.getName()), campaign);

        //Validate form input
        HttpHeaders headers = giveawayService.validateGiveawayData(giveaway);

        //Validate image size & file type
        String extension = FileUtils.resolveExtension(photo.getContentType());
        if(FileUtils.isImage(extension)) {
            if(FileUtils.checkDimensions(photo, GiveawayService.MIN_ALLOWED_SIZE, 
                                         GiveawayService.MAX_ALLOWED_SIZE, GiveawayService.MIN_ALLOWED_SIZE, 
                                         GiveawayService.MAX_ALLOWED_SIZE, true)) {
                headers.add("Error-Giveaway-Image-Size", "Giveaway photo must be square and between 64-612 pixels.");
            }
        } else {
            headers.add("Error-Giveaway-Image-Type", "Only .jpg and .png file types are allowed.");
        }

        //If headers are not empty, then there's either validation or input errors 
        if(!headers.isEmpty()) {
            return new ResponseEntity<>(headers, HttpStatus.BAD_REQUEST);
        } else {
            giveaway.setPhotoExtension(extension);
            giveaway.setStatus(GiveawayStatus.INACTIVE);
            giveaway = giveawayService.save(giveaway);

            FileUtils.uploadResource(photo, giveaway.getGiveawayId() + extension, GiveawayService.GIVEAWAY_STORING_LOCATION);

            return new ResponseEntity<>(HttpStatus.CREATED);
        }

    }
}

Here's the giveaway POJO:

@Entity
@Table(name="GIVEAWAYS")
public class Giveaway implements Serializable {

    private static final long serialVersionUID = -8835490774774467020L;

    @Id
    @Column(name="giveaway_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long giveawayId;

    @ManyToOne
    @JoinColumn(name="campaign_id", foreignKey=@ForeignKey(name="give_campaign_id"), nullable=false)
    private Campaign campaign;

    @Column(name="giveaway_item")
    private String giveawayItem;

    @Column(name="description")
    private String description;

    @Column(name="photo_extension")
    private String photoExtension;

    @Column(name="amount_of_items")
    private int amountOfItems;

    @Column(name="status")
    private String status;

    @Column(name="eligibility")
    private String eligibility;

   //Getters and setters below...

And here's the JSON created from the form sent to the back end:

{giveawayItem: "testing", description: "test123", amountOfItems: 4, eligibility: "Followers"}

EDIT 3 Whenever I use angular.toJson or JSON.stringify on the data above, it turns it into this:

{"description":"dfgdg","amountOfItems":5,"eligibility":"Followers"}

For some reason, giveawayItem disappears. I don't know if that's causing any issues, but it's certainly troubling.

EDIT 4

Debug logging

2016-10-31 13:40:35.097 DEBUG 2716 --- [nio-8090-exec-3] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing PUT request for [/dashboard/campaigns/1/giveaways]
2016-10-31 13:40:35.098 DEBUG 2716 --- [nio-8090-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /dashboard/campaigns/1/giveaways
2016-10-31 13:40:35.102 DEBUG 2716 --- [nio-8090-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public org.springframework.http.ResponseEntity<java.lang.String> com.glimpsmedia.app.controllers.GiveawayController.addGiveaway(com.glimpsmedia.app.model.Giveaway,org.springframework.web.multipart.MultipartFile,long,java.security.Principal) throws java.lang.Exception]
2016-10-31 13:40:35.121 DEBUG 2716 --- [nio-8090-exec-3] o.s.web.cors.DefaultCorsProcessor        : Skip CORS processing: request is from same origin
2016-10-31 13:40:35.139 DEBUG 2716 --- [nio-8090-exec-3] .w.s.m.m.a.ServletInvocableHandlerMethod : Error resolving argument [0] [type=com.glimpsmedia.app.model.Giveaway]
HandlerMethod details: 
Controller [com.glimpsmedia.app.controllers.GiveawayController]
Method [public org.springframework.http.ResponseEntity<java.lang.String> com.glimpsmedia.app.controllers.GiveawayController.addGiveaway(com.glimpsmedia.app.model.Giveaway,org.springframework.web.multipart.MultipartFile,long,java.security.Principal) throws java.lang.Exception]


org.springframework.web.bind.MissingServletRequestParameterException: Required Giveaway parameter 'giveaway' is not present
    at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:195) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:104) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114) [spring-webmvc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) [spring-webmvc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) [spring-webmvc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) [spring-webmvc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) [spring-webmvc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) [spring-webmvc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) [spring-webmvc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:883) [spring-webmvc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:651) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) [spring-webmvc-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-embed-websocket-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:158) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at com.glimpsmedia.app.security.StatelessAuthenticationFilter.doFilter(StatelessAuthenticationFilter.java:52) [classes/:na]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:121) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at com.glimpsmedia.app.security.CsrfTokenFilter.doFilterInternal(CsrfTokenFilter.java:46) [classes/:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:124) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) [spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:522) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1110) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:785) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1425) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_91]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_91]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.4.jar:8.5.4]
    at java.lang.Thread.run(Unknown Source) [na:1.8.0_91]

2016-10-31 13:40:35.140 DEBUG 2716 --- [nio-8090-exec-3] .m.m.a.ExceptionHandlerExceptionResolver : Resolving exception from handler [public org.springframework.http.ResponseEntity<java.lang.String> com.glimpsmedia.app.controllers.GiveawayController.addGiveaway(com.glimpsmedia.app.model.Giveaway,org.springframework.web.multipart.MultipartFile,long,java.security.Principal) throws java.lang.Exception]: org.springframework.web.bind.MissingServletRequestParameterException: Required Giveaway parameter 'giveaway' is not present
2016-10-31 13:40:35.140 DEBUG 2716 --- [nio-8090-exec-3] .w.s.m.a.ResponseStatusExceptionResolver : Resolving exception from handler [public org.springframework.http.ResponseEntity<java.lang.String> com.glimpsmedia.app.controllers.GiveawayController.addGiveaway(com.glimpsmedia.app.model.Giveaway,org.springframework.web.multipart.MultipartFile,long,java.security.Principal) throws java.lang.Exception]: org.springframework.web.bind.MissingServletRequestParameterException: Required Giveaway parameter 'giveaway' is not present
2016-10-31 13:40:35.140 DEBUG 2716 --- [nio-8090-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolving exception from handler [public org.springframework.http.ResponseEntity<java.lang.String> com.glimpsmedia.app.controllers.GiveawayController.addGiveaway(com.glimpsmedia.app.model.Giveaway,org.springframework.web.multipart.MultipartFile,long,java.security.Principal) throws java.lang.Exception]: org.springframework.web.bind.MissingServletRequestParameterException: Required Giveaway parameter 'giveaway' is not present
2016-10-31 13:40:35.141 DEBUG 2716 --- [nio-8090-exec-3] o.s.web.servlet.DispatcherServlet        : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2016-10-31 13:40:35.141 DEBUG 2716 --- [nio-8090-exec-3] o.s.web.servlet.DispatcherServlet        : Successfully completed request
2016-10-31 13:40:35.142 DEBUG 2716 --- [nio-8090-exec-3] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing PUT request for [/error]
2016-10-31 13:40:35.142 DEBUG 2716 --- [nio-8090-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error
2016-10-31 13:40:35.144 DEBUG 2716 --- [nio-8090-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)]
2016-10-31 13:40:35.144 DEBUG 2716 --- [nio-8090-exec-3] o.s.web.cors.DefaultCorsProcessor        : Skip CORS processing: request is from same origin
2016-10-31 13:40:35.149 DEBUG 2716 --- [nio-8090-exec-3] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Written [{timestamp=Mon Oct 31 13:40:35 EDT 2016, status=400, error=Bad Request, exception=org.springframework.web.bind.MissingServletRequestParameterException, message=Required Giveaway parameter 'giveaway' is not present, path=/dashboard/campaigns/1/giveaways}] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@7cbe3a05]
2016-10-31 13:40:35.149 DEBUG 2716 --- [nio-8090-exec-3] o.s.web.servlet.DispatcherServlet        : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2016-10-31 13:40:35.149 DEBUG 2716 --- [nio-8090-exec-3] o.s.web.servlet.DispatcherServlet        : Successfully completed request

Upvotes: 2

Views: 1974

Answers (3)

Fevly Pallar
Fevly Pallar

Reputation: 3109

Here's my interpretation of your problem.

Actually you're struggling to transmit the object from the Angular front side and trying to get it through @RequestParam which is naturally can't be straightforward as @RequestParam will normally works on string type, means it can't just map a complex object . It's all makes sense as the 400 http code is indicating a malformed request.

A possible solution (notice that @RequestBody instead of @RequestParam on Giveaway ):

// Angular side
$scope.addGiveaway = function(campaignId){
        var photo = $scope.photo;
        var giveaway = $scope.giveaway;
        var data = new FormData();
        data.append('photo', photo);
        data.append('giveaway', giveaway);
        var uploadUrl = "/dashboard/campaigns/"+campaignId+"/giveaways";
        $http.put(uploadUrl, data, {
            transformRequest: angular.identity,
            headers: {
                'Content-Type': 'multipart/form-data',
            }
        });


// Spring side
 @RequestMapping(method = RequestMethod.PUT)
    public ResponseEntity<String> addGiveaway(@RequestBody Giveaway giveaway, 
                                              @RequestParam("photo") MultipartFile photo,
                                              @PathVariable("campaignId") long campaignId,
                                              Principal principal) throws Exception {

Upvotes: 0

Jake Miller
Jake Miller

Reputation: 2652

I fixed it. I changed the Giveaway object to a String and parsed that with an ObjectMapper. Here's my new controller:

@RequestMapping(method = RequestMethod.PUT)
    public ResponseEntity<String> addGiveaway(@RequestParam("giveaway") String giveawayData, 
                                              @RequestParam("photo") MultipartFile photo,
                                              @PathVariable("campaignId") long campaignId,
                                              Principal principal) throws Exception {

I then used var giveaway = angular.toJson($scope.giveaway) to format the json properly. I then appended the giveaway data to the end of the request instead of adding it to the form data, like this:

'.../giveaways?giveaway=' + giveaway;

Upvotes: 0

Vasu
Vasu

Reputation: 22462

Your request url /dashboard/campaigns/"+campaignId+"/giveaways is not actually mapped to the controller method.

As you need to pass campaignId as @PathVariable, you should map it, in your controller method.

Class Level Mapping (at top): /dashboard/campaigns/

Method Level Mapping : {campaignId}/giveaways

The code follows below:

    @RestController(value = "/dashboard/campaigns/") {
    public class GiveawayController {
           @RequestMapping(value="{campaignId}/giveaways", method =RequestMethod.PUT)
    public ResponseEntity<String> addGiveaway(    
             @RequestParam("giveaway")Giveaway giveaway, 
             @RequestParam("photo") MultipartFile photo,
             @PathVariable("campaignId") long campaignId,
              Principal principal) throws Exception {
             //code here
        }
    }

P.S.: I have assumed that /dashboard/campaigns/ mapping at class level.

Upvotes: 1

Related Questions