在Jersey的身体请求中POST JSON

我有一个Java动态Web项目(部署在本地应用程序服务器Tomcat 7上),它使用Jersey创建REST API。

我不使用任何构建自动化工具(因此我的库被添加到构建路径,并且servlet被插入到web.xml文件中)。

我正在使用的库是:

asm-3.1.jar gson-2.2.1.jar jersey-client-1.0.3.jar jersey-core-1.0.3.jar jersey-json-1.18.jar jersey-server-1.0.3.jar jettison-1.1.jar jsr311-api-1.0.jar mysql-connector-java-5.0.8-bin.jar 

我的web.xml如下:

   UserAccount  ServletAdaptor com.sun.jersey.server.impl.container.servlet.ServletAdaptor  com.sun.jersey.api.json.POJOMappingFeature true  1   ServletAdaptor /rest/*   

该应用程序正在与MySQL数据库进行交互。 方案如下:数据库包含名为users的用户帐户表。 列是id,名称,用户名和密码。

我有一个POST方法来validation帐户(用户名+密码)是否有效。 (用户名和密码作为标题参数传递) http:// localhost:8080 / UserAccount / rest / login / doLogin和标题:用户名:x密码:1234

 @POST @Path("/doLogin") @Produces(MediaType.APPLICATION_JSON) public String doLogin(@HeaderParam("username") String uname, @HeaderParam("password") String pwd){ String response = ""; if(checkCredentials(uname, pwd)){ response = Utility.constructJSON("login",true); }else{ response = Utility.constructJSON("login", false, "Incorrect Email or Password"); } return response; } 

如您所见,如果用户帐户有效,响应将生成一个带有true或false的JSON。 到目前为止它工作正常。 它也可以正常执行GET并将params作为查询参数传递(但这不是重点)。

现在我正在尝试POST,但这次在JSON正文中传递用户名和密码:

 { "username":"x", "password":"1234" } 

为此,我创建了一个名为User.java的类:

 @XmlRootElement() @XmlAccessorType(XmlAccessType.FIELD) public class User implements Serializable { /** * */ private static final long serialVersionUID = 1L; @XmlElement(name="username") private String username; @XmlElement(name="password") private String password; public String getUsername() { return username; } public String getPassword() { return password; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } @Override public String toString() { // TODO Auto-generated method stub return "username: " + username; } } 

我创建了一个方法:

  //pass the arguments as JSON body @POST // Path: http://localhost:8080/UserAccount/rest/login/asklogin @Path("/askLogin") // Produces JSON as response @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response askLogin(User user) { System.out.println("Inside POST askLogin"); if(checkCredentials(user.getUsername(), user.getPassword())) { return Response.ok().build(); } else { return Response.serverError().build(); } } 

我正在使用Google Chrome中的Advanced Rest Client和Firefox中的REST Easy来测试API。

我还创建了一个实现MessageBodyReader的类,如下所示:

 @Provider public class UserBeanMessageBodyReader implements MessageBodyReader { //used for MessageBodyReader @Override public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { return type == User.class; } @Override public User readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { try { JAXBContext jaxbContext = JAXBContext.newInstance(User.class); User user = (User) jaxbContext.createUnmarshaller().unmarshal(entityStream); return user; } catch (JAXBException jaxbException) { jaxbException.printStackTrace(); System.out.println("Error deserializing a User" + jaxbException); } return null; } } 

调试后,问题出现在这里:

 User user = (User) jaxbContext.createUnmarshaller().unmarshal(entityStream); 

它继续捕获声明。

堆栈跟踪如下:

  INFO: Server startup in 1239 ms javax.xml.bind.UnmarshalException - with linked exception: [org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.] at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:563) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:249) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:204) at ro.useraccount.jersey.UserBeanMessageBodyReader.readFrom(UserBeanMessageBodyReader.java:36) at ro.useraccount.jersey.UserBeanMessageBodyReader.readFrom(UserBeanMessageBodyReader.java:1) at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:393) at com.sun.jersey.server.impl.model.method.dispatch.EntityParamDispatchProvider$EntityInjectable.getValue(EntityParamDispatchProvider.java:139) at com.sun.jersey.server.impl.inject.InjectableValuesProvider.getInjectableValues(InjectableValuesProvider.java:43) at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$EntityParamInInvoker.getParams(AbstractResourceMethodDispatchProvider.java:126) at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:173) at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:67) at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:163) at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:111) at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:71) at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:111) at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:63) at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:654) at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:612) at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:603) at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:309) at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:425) at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:590) at javax.servlet.http.HttpServlet.service(HttpServlet.java:723) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:612) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:503) at java.lang.Thread.run(Thread.java:745) Caused by: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog. at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203) at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177) at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400) at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327) at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1437) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:999) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:118) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213) at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243) ... 35 more Error deserializing a Userjavax.xml.bind.UnmarshalException - with linked exception: [org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Content is not allowed in prolog.] Inside POST askLogin Oct 06, 2016 8:57:27 AM org.apache.catalina.core.StandardWrapperValve invoke SEVERE: Servlet.service() for servlet ServletAdaptor threw exception java.lang.NullPointerException at ro.useraccount.jersey.Login.askLogin(Login.java:67) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:175) at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:67) at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:163) at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:111) at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:71) at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:111) at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:63) at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:654) at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:612) at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:603) at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:309) at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:425) at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:590) at javax.servlet.http.HttpServlet.service(HttpServlet.java:723) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:612) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:503) at java.lang.Thread.run(Thread.java:745) 

你怎么看?

您应该告诉Jersey使用Gson进行JSON处理。 您可以这样做来实现Jersey提供的MessageBodyReaderMessageBodyWriter接口。 在此stackoverflow问题中,您可以找到一个示例(请参阅接受的答案)。 如果要为其添加一些上下文,请查看Jersey 1.x手册的JSON部分

编辑:我可能不理解您的代码,但在UserBeanMessageBodyReader调用Gson的位置是什么? 尝试使用类似的东西来reaedFrom方法

 String result = new BufferedReader(new InputStreamReader(entityStream)) .lines().collect(Collectors.joining("\n")); Gson gson = new GSon(); User myUser = gson.fromJson(result, User.class); 

而不是使用JAXBContext (它只能理解XML输入)。