服务重定向

301 Moved Permanently:
URI uri = ...
return Response.status(Status.MOVED_PERMANENTLY).location(uri).build();
303 See Other (aka POST/redirect/GET):
URI uri = ...
return Response.seeOther(uri).build();
307 Temporary Redirect:
URI uri = ...
return Response.temporaryRedirect(uri).build();
For more details, the Response class documentation may be useful.

Other details that can be useful when using JAX-RS
You also can inject the UriInfo in your REST endpoints:

@Context
UriInfo uriInfo;
And get some useful information, such as the base URI and the absolute path of the request. It will be useful when building the URI for redirection.

A resource method with redirection will be like:

@Path("/foo")
public class MyEndpoint {

    @Context
    private UriInfo uriInfo;

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public Response myMethod() {
        URI uri = uriInfo.getBaseUriBuilder().path("bar").build();
        return Response.temporaryRedirect(uri).build();
    }
}

Response.temporaryRedirect(uriInfo.getBaseUriBuilder().path("/").build()).build();这样是直接跳转到根路径下,需要注意的是这个方法的跳转方式GET,POST等会延用进入该方法时的方法,如果是POST方法进入的那么跳转后的方法还是post。

Response.seeOther(uriInfo.getBaseUriBuilder().path("/").build()).build();这样的跳转方式也是直接跳到根路径下,这种方式下的跳转采用的是GET方法

JSP中response.sendRedirect()与request.getRequestDispatcher().forward(request,response)这两个对象都可以使页面跳转,但是二者是有很大的区别的,分条来说,有以下几点:

①response.sendRedirect(url)-----重定向到指定URL 

request.getRequestDispatcher(url).forward(request,response) -----请求转发到指定URL

②response.sendRedirect(url)-----是客户端跳转

request.getRequestDispatcher(url).forward(request,response) -----是服务器端跳转

③response.sendRedirect(url)跳转到指定的URL地址后,上个页面(跳转之前的原来页面)中的请求全部结束,原request对象将会消亡,数据将会消失。紧接着,当前新页面会新建request对象,即产生新的request对象。

【详细过程:redirect 会首先发一个response给浏览器,然后浏览器收到这个response后再发一个requeset给服务器,服务器接收后发新的response给浏览器。这时页面从浏览器获取来的是一个新的request。这时,在原来跳转之前的页面用request.setAttribute存的东西都没了,如果在当前的新页面中用request.getAttribute取,得到的将会是null。】

request.getRequestDispatcher(url).forward(request,response)是采用请求转发方式,在跳转页面的时候是带着原来页面的request和response跳转的,request对象始终存在,不会重新创建。

【详细过程:forward 发生在服务器内部, 是在浏览器完全不知情的情况下发给了浏览器另外一个页面的response. 这时页面收到的request不是从浏览器直接发来的,可能是在转页时己经用request.setAttribute在request里放了数据,在转到的页面就可以直接用request.getAttribute获得数据了。】

④使用response.sendRedirect()地址栏中的网址将改变

使用request.getRequestDispatcher().forward(request,response)地址栏中的网址保持不变。

⑤使用response.sendRedirect()时如果需要传递参数,那只能在url后加参数,如:url?id=1,而不能通过request或response方式。

使用request.getRequestDispatcher().forward(request,response)如果需要传递参数,可以在程序内通过response.setAttribute("name",name)来传至下一个页面.而不能在后面带参数传递,比如servlet?name=frank这样不行。

⑥运用sendRedirect()方法可以让你重定向到任何URL,而forward()方法只能重定向到同一个Web应用程序中的某个资源。

表单form中的action="/uu";sendRedirect("/uu");表示相对于服务器根路径。如服务器根路径是http://localhost:8080/Test则提交至http://localhost:8080/uu;而Forward代码中的"/uu"则代表相对于WEB应用的路径。如http://localhost:8080/Test应用则提交至http://localhost:8080/Test/uu。

⑦运用HttpServletResponse接口的sendRedirect()方法

sendRedirect()是在用户的浏览器端工作,同时它可以重定向至不同的主机上,sendRedirect()可以重定向有frame的jsp文件。
假设转发代码包含于注册的servlet-url为/ggg/tt;jsp为/ggg/tt.jsp。
绝对路径:response.sendRedirect("http://www.brainysoftware.com")发送至http://www.brainysoftware.com
根路径:response.sendRedirect("/ooo")发送至http://localhost:8080/ooo
相对路径:response.sendRedirect("ooo")发送至http://localhost:8080/Test/ggg/ooo。

sendRedirect等同于此方式:
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
String newLocn = "/newpath/jsa.jsp";
response.setHeader("Location",newLocn);
⑧运用RequestDispatcher接口的Forward()方法 
forward()无法重定向至有frame的jsp文件,可以重定向至有frame的html文件,
只有在客户端没有输出时才可以调用forward方法。如果当前页面的缓冲区(buffer)不是空的,那么你在调用forward方法前必须先清空缓冲区。
"/"代表相对与web应用路径 
RequestDispatcher rd = request.getRequestDispatcher("/ooo");
rd.forward(request, response);提交至http://localhost:8080/Test/ooo

RequestDispatcher rd = getServletContext().getRequestDispatcher("/ooo");
rd.forward(request, response);提交至http://localhost:8080/Test/ooo

RequestDispatcher rd =getServletContext().getNamedDispatcher("TestServlet");(TestServlet为一个<servlet-name>)
rd.forward(request, response);提交至名为TestServlet的servlet

如果在<jsp:forward>之前有很多输出,前面的输出已使缓冲区满,将自动输出到客户端,那么该语句将不起作用,这一点应该特别注意。
另外要注意:它不能改变浏览器地址,刷新的话会导致重复提交。
从http://localhost:8080/Test/gw/page.jsp中转发
<jsp:forward page="OtherPage.jsp"/>在JSP页面被解析后转换成pageContext.forward("OtherPage.jsp");
"/OtherPage.jsp"提交到http://localhost:8080/Test/OtherPage.jsp
"OtherPage.jsp"提交到http://localhost:8080/Test/gw/OtherPage.jsp

此外,除了这两种页面跳转方法,还有一种比较方便的方法:

Meta Refresh方法
这种方法是由HTML提供的,Meta本身就是HTML标签。使用方法是:

<meta http-equiv="refresh" content="5; url=http://www.dreamdu.com/" />
相应的java代码是:
String content=stayTime+";URL="+URL;
response.setHeader("REFRESH",content);

响应码 含义
100 继续
101 分组交换协议
200 OK
201 被创建
202 被采纳
203 非授权信息
204 无内容
205 重置内容
206 部分内容
300 多选项
301 永久地传递
302 找到
303 参见其他
304 未改动
305 使用代理
307 暂时重定向
400 错误请求
401 未授权
402 要求付费
403 禁止
404 未找到
405 不允许的方法
406 不被采纳
407 要求代理授权
408 请求超时
409 冲突
410 过期的
411 要求的长度
412 前提不成立
413 请求实例太大
414 请求URL太大
415 不支持的媒体类型
416 无法满足的请求范围
417 失败的预期
500 内部错误
501 未被使用
502 网关错误
503 不可用的服务
504 网关超时
505 HTTP版本未被支持

一、成功

从 200 到 399 为成功码,表示请求处理成功。

如果方法返回值不为null,则返回码是 200;如果返回值为 null 或者为 void,则返回码为 204,表示无内容。

二、错误

从 400 到 599 表示处理错误。

例如 404表示网页未找着;如果请求的期望的返回交换类型不对,则返回 406,表示不可接爱;如果请求的方法未找着,则返回 405,表示方法不允许,这个返回结果对于HEAD和OPTIONS请求方法例外,对于HEAD会试图去查找能处理相同URI的GET方法;对于OPTION,会返回一些自动生成的信息。

三、复杂的响应

对于不能简单处理的返回信息,则可以返回javax.ws.rs.core.Response对象:

Java代码  收藏代码

  1. public abstract class Response {  
  2.   
  3.     public abstract Object getEntity();  
  4.     public abstract int getStatus();  
  5.     public abstract MultivaluedMap<String, Object> getMetadata();  
  6.     ...  
  7.   
  8. }  

Response对象不能直接创建,需要通过javax.ws.rs.core.Response.ResponseBuilder来创建:

Java代码  收藏代码

  1. public abstract class Response {  
  2.   
  3.     ...  
  4.     public static ResponseBuilder status(Status status) {...}  
  5.     public static ResponseBuilder status(int status) {...}  
  6.     public static ResponseBuilder ok() {...}  
  7.     public static ResponseBuilder ok(Object entity) {...}  
  8.     public static ResponseBuilder ok(Object entity, MediaType type) {...}  
  9.     public static ResponseBuilder ok(Object entity, String type) {...}  
  10.     public static ResponseBuilder ok(Object entity, Variant var) {...}  
  11.     public static ResponseBuilder serverError() {...}  
  12.     public static ResponseBuilder created(URI location) {...}  
  13.     public static ResponseBuilder noContent() {...}  
  14.     public static ResponseBuilder notModified() {...}  
  15.     public static ResponseBuilder notModified(EntityTag tag) {...}  
  16.     public static ResponseBuilder notModified(String tag) {...}  
  17.     public static ResponseBuilder seeOther(URI location) {...}  
  18.     public static ResponseBuilder temporaryRedirect(URI location) {...}  
  19.     public static ResponseBuilder notAcceptable(List<Variant> variants) {...}  
  20.     public static ResponseBuilder fromResponse(Response response) {...}  
  21.     ...  
  22.   
  23. }  

ResponseBuilder是一个用来创建单个Response实例的工厂类, 首先将要创建的response对象的状态存起来,最后当状态设置完成了,就使用builder去初始化Response:

Java代码  收藏代码

  1. public static abstract class ResponseBuilder {  
  2.   
  3.     public abstract Response build();  
  4.   
  5.     public abstract ResponseBuilder clone();  
  6.     public abstract ResponseBuilder status(int status);  
  7.   
  8.     public ResponseBuilder status(Status status) {...}  
  9.   
  10.     public abstract ResponseBuilder entity(Object entity);  
  11.     public abstract ResponseBuilder type(MediaType type);  
  12.     public abstract ResponseBuilder type(String type);  
  13.     public abstract ResponseBuilder variant(Variant variant);  
  14.     public abstract ResponseBuilder variants(List<Variant> variants);  
  15.     public abstract ResponseBuilder language(String language);  
  16.     public abstract ResponseBuilder language(Locale language);  
  17.     public abstract ResponseBuilder location(URI location);  
  18.     public abstract ResponseBuilder contentLocation(URI location);  
  19.     public abstract ResponseBuilder tag(EntityTag tag);  
  20.     public abstract ResponseBuilder tag(String tag);  
  21.     public abstract ResponseBuilder lastModified(Date lastModified);  
  22.     public abstract ResponseBuilder cacheControl(CacheControl cacheControl);  
  23.     public abstract ResponseBuilder expires(Date expires);  
  24.     public abstract ResponseBuilder header(String name, Object value);  
  25.     public abstract ResponseBuilder cookie(NewCookie... cookies);  
  26. }  

例如:

Java代码  收藏代码

  1. @Path("/textbook")  
  2. public class TextBookService {  
  3.   
  4.     @GET  
  5.     @Path("/restfuljava")  
  6.     @Produces("text/plain")  
  7.     public Response getBook() {  
  8.         String book = ...;  
  9.         ResponseBuilder builder = Response.ok(book);  
  10.         builder.language("fr").header("Some-Header", "some value");  
  11.         return builder.build();  
  12.     }  
  13.   
  14. }  

四、Cookie

JAX-RS使用了一个简单的类去表示一个cookie值,它就是javax.ws.rs.core.NewCookie:

Java代码  收藏代码

  1. public class NewCookie extends Cookie {  
  2.   
  3.     public static final int DEFAULT_MAX_AGE = −1;  
  4.     public NewCookie(String name, String value) {}  
  5.     public NewCookie(String name, String value, String path,  
  6.     String domain, String comment,  
  7.     int maxAge, boolean secure) {}  
  8.     public NewCookie(String name, String value, String path,  
  9.             String domain, int version, String comment,  
  10.     int maxAge, boolean secure) {}  
  11.     public NewCookie(Cookie cookie) {}  
  12.     public NewCookie(Cookie cookie, String comment,  
  13.     int maxAge, boolean secure) {}  
  14.     public static NewCookie valueOf(String value)  
  15.             throws IllegalArgumentException {}  
  16.     public String getComment() {}  
  17.     public int getMaxAge() {}  
  18.     public boolean isSecure() {}  
  19.     public Cookie toCookie() {}  
  20.   
  21. }  

要返回Cookie,只需要传入它到Response中:

Java代码  收藏代码

  1. @GET  
  2. public Response get() {  
  3.     NewCookie cookie = new NewCookie("key", "value);  
  4.     ResponseBuilder builder = Response.ok("hello", "text/plain");  
  5. return builder.cookies(cookie).build();  
  6. }  

五、状态类别

除了直接写数据外,JAX-RS定义了一个状态值的枚举类别:

Java代码  收藏代码

  1. public enum Status {  
  2.     OK(200, "OK"),  
  3.     CREATED(201, "Created"),  
  4.     ACCEPTED(202, "Accepted"),  
  5.     NO_CONTENT(204, "No Content"),  
  6.     MOVED_PERMANENTLY(301, "Moved Permanently"),  
  7.     SEE_OTHER(303, "See Other"),  
  8.     NOT_MODIFIED(304, "Not Modified"),  
  9.     TEMPORARY_REDIRECT(307, "Temporary Redirect"),  
  10.     BAD_REQUEST(400, "Bad Request"),  
  11.     UNAUTHORIZED(401, "Unauthorized"),  
  12.     FORBIDDEN(403, "Forbidden"),  
  13.     NOT_FOUND(404, "Not Found"),  
  14.     NOT_ACCEPTABLE(406, "Not Acceptable"),  
  15.     CONFLICT(409, "Conflict"),  
  16.     GONE(410, "Gone"),  
  17.     PRECONDITION_FAILED(412, "Precondition Failed"),  
  18.     UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"),  
  19.     INTERNAL_SERVER_ERROR(500, "Internal Server Error"),  
  20.     SERVICE_UNAVAILABLE(503, "Service Unavailable");  
  21.   
  22.     public enum Family {  
  23.         INFORMATIONAL, SUCCESSFUL, REDIRECTION,  
  24.         CLIENT_ERROR, SERVER_ERROR, OTHER  
  25.     }  
  26.   
  27.     public Family getFamily()  
  28.     public int getStatusCode()  
  29.     public static Status fromStatusCode(final int statusCode)  
  30. }  

每个Status的值都关联的到一个特定HTTP的返回值族,这个族由Status.Family标识。例如 100范围的值被认识是信息性的;200范围的是成功;300范围的也是成功,但是被重定向的;400是client错误;500是服务器错误。

Response.status()和ResponseBuilder.status()都接受一个Status值,例如:

    

Java代码  收藏代码

  1. @DELETE  
  2. Response delete() {  
  3.   
  4.     ...  
  5.     return Response.status(Status.GONE).build();  
  6.   
  7. }  

六、javax.ws.rs.core.GenericEntity

当处理Response的返回对象(entity)时,如果是一个类似于MessageBodyWriter这样的支持泛型的对象,则问题来了: isWriteable()方法需要有泛弄的信息。然后不幸的是java的泛型信息只存在编译时,不存在运行时,因此没有一个简单的方法可以得到在运行时得到泛型的信息,因此MessageBodyWriter不知道如何输出对象。

为了解决这个问题,JAX-RS提供了一个帮助类 javax.ws.rs.core.GenericEntity 。例如:

Java代码  收藏代码

  1. @GET  
  2. @Produces("application/xml")  
  3. public Response getCustomerList() {  
  4.     List<Customer> list = new ArrayList<Customer>();  
  5.     list.add(new Customer(...));  
  6.     GenericEntity entity = new GenericEntity<List<Customer>>(list){};  
  7.     return Response.ok(entity);  
  8. }  

GenericEntity也是一个泛型模板,只需要将输出entity的泛型信息加到它上,并且把对象做为一个参数传入即可。

七、javax.ws.rs.WebApplicationException

WebApplicationException是一个内置、非检测异常,支持传入Response对象或者状态码:

Java代码  收藏代码

  1. public class WebApplicationException extends RuntimeException {  
  2.   
  3.     public WebApplicationException() {...}  
  4.     public WebApplicationException(Response response) {...}  
  5.     public WebApplicationException(int status) {...}  
  6.     public WebApplicationException(Response.Status status) {...}  
  7.     public WebApplicationException(Throwable cause) {...}  
  8.     public WebApplicationException(Throwable cause,  
  9.                             Response response) {...}  
  10.     public WebApplicationException(Throwable cause, int status) {...}  
  11.     public WebApplicationException(Throwable cause,  
  12.     Response.Status status) {...}  
  13.     public Response getResponse() {...]  
  14. }  

当JAX-RS碰到一个WebApplicationException抛出时,它就捕获这个异常,调用它的getResponse()方法去获取Response,发回给client端。 如果应用以一个状态码或者Response初始化了WebApplicationException,则这个状态码或者Response将被用来创建真正的HTTP响应;或者,会直接返回 500, “Internal Server Error“给客户端,例如:

Java代码  收藏代码

  1. @Path("/customers")  
  2. public class CustomerResource {  
  3.   
  4.     @GET  
  5.     @Path("{id}")  
  6.     @Produces("application/xml")  
  7.     public Customer getCustomer(@PathParam("id") int id) {  
  8.         Customer cust = findCustomer(id);  
  9.         if (cust == null) {  
  10.             throw new WebApplicationException(Response.Status.NOT_FOUND);  
  11.         }  
  12.         return cust;  
  13.     }  
  14. }  

这里如果没找着客户,会返回404错误

八、错误匹配

应用中可能有各种各样的,来自应用或者第三方包的异常,如果仅依赖于容器提供的错误处理方式,则可能灵活度不够: 捕获这些异常,然后包装到WebApplicationException中会让人觉得相当乏味。

这里的另外一种选择就是使用javax.ws.rs.ext.ExceptionMapper,这个对象知道怎么匹配一个抛出的异常到一个Repsonse对象上:

Java代码  收藏代码

  1. public interface ExceptionMapper<E extends Throwable> {  
  2.     Response toResponse(E exception);  
  3. }  

例如对于JPA有EntityNotFoundException:

Java代码  收藏代码

  1. @Provider  
  2. public class EntityNotFoundMapper  
  3. implements ExceptionMapper<EntityNotFoundException> {  
  4.       
  5.       public Response toResponse(EntityNotFoundException e) {  
  6.            return Response.status(Response.Status.NOT_FOUND).build();  
  7.       }  
  8. }  

注: ExceptionMapper的实现,必须加上@Provider注释

  

ExceptionMapper也支持异常层级关系,例如A 继承 B,如果找不到A的mapper,则会向上查找B的mapper。

最后ExceptionMapper使用JAX-RS的deployment API进行注册,可以用Application.

ref:https://stackoverflow.com/questions/36638150/best-approach-to-redirect-an-url-using-rest

https://blog.csdn.net/qinzhenhua100/article/details/53227841

https://blog.csdn.net/RookieThree/article/details/75646429

https://blog.csdn.net/u013615806/article/details/51792100

猜你喜欢

转载自blog.csdn.net/zhouyan8603/article/details/81952473