Getting started with MVC(5)

4609 ワード

Handle PUT and DELETE request
When you try to submit aPUTorDELETEhttp request via form submission, and you want to invoke the methods annotated with@PUTor@DELETEin the Controller to handle the request.
Unfortunately it does not work.
There is a simple solution which can help us to overcome this issue.
If you have used Spring MVC before and I think you could know there is aHiddenMethodFilterin the Spirng MVC to fix this issue. Java EE 8 MVC does not ship the similar Filter, we can create one.
Solution
  • Create a Filter to convert the request method to the target HTTP method.
    @WebFilter(filterName = "HiddenHttpMethodFilter", urlPatterns = {"/*"}, dispatcherTypes = {DispatcherType.REQUEST})
    public class HiddenHttpMethodFilter implements Filter {
    
        @Inject
        Logger log;
    
        /**
        * Default method parameter: {@code _method}
        */
        public static final String DEFAULT_METHOD_PARAM = "_method";
    
        private String methodParam = DEFAULT_METHOD_PARAM;
    
        /**
        * Set the parameter name to look for HTTP methods.
        *
        * @see #DEFAULT_METHOD_PARAM
        */
        public void setMethodParam(String methodParam) {
            this.methodParam = methodParam;
        }
    
        @Override
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
                throws ServletException, IOException {
            log.log(Level.INFO, "entering HttpHiddenFilter...");
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
    
            String paramValue = request.getParameter(this.methodParam);
            log.log(Level.INFO, "paramValue @" + paramValue);
            log.log(Level.INFO, "request method @" + request.getMethod());
    
            if ("POST".equals(request.getMethod()) && paramValue != null && paramValue.trim().length() > 0) {
                String method = paramValue.toUpperCase(Locale.ENGLISH);
                HttpServletRequest wrapper = new HttpMethodRequestWrapper(request, method);
                filterChain.doFilter(wrapper, response);
            } else {
                filterChain.doFilter(request, response);
            }
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void destroy() {
    
        }
    
        /**
        * Simple {@link HttpServletRequest} wrapper that returns the supplied
        * method for {@link HttpServletRequest#getMethod()}.
        */
        private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
    
            private final String method;
    
            public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
                super(request);
                this.method = method;
            }
    
            @Override
            public String getMethod() {
                return this.method;
            }
        }
    
    }
  • Add a hidden field named_methodin the form, which value is the target HTTP method.
    <form action="${markDoingUrl}" method="post">
        <input type="hidden" name="_method" value="PUT"><jsp:text /></input>
        <input type="hidden" name="status" value="DOING"><jsp:text /></input>
        <button type="submit" class="btn btn-sm btn-primary">
            <span class="glyphicon glyphicon-play" aria-hidden="true"><jsp:text /></span>
            START
        </button>
    </form>
  • The@PUTmethod in theTaskController.
    @PUT
    @Path("{id}/status")
    public Response updateStatus(@PathParam(value = "id") Long id, @NotNull @FormParam(value = "status") String status) {
        log.log(Level.INFO, "updating status of the existed task@id:{0}, status:{1}", new Object[]{id, status});
    
        Task task = taskRepository.findById(id);
    
        task.setStatus(Task.Status.valueOf(status));
    
        taskRepository.update(task);
    
        flashMessage.notify(Type.info, "Task status was updated successfully!");
    
        return Response.ok("redirect:tasks").build();
    }

  • Source codes
  • Clone the codes from my github.com account. https://github.com/hantsy/ee8-sandbox/
  • Open the mvc project in NetBeans IDE.
  • Run it on Glassfish.
  • After it is deployed and runging on Glassfish application server, navigate http://localhost:8080/ee8-mvc/mvc/tasks in browser.