Introducción al servicio de descanso
Restful Service es un modelo arquitectónico que se ha vuelto más popular en los últimos años. Su servicio web ligero reproduce el nativo Get, Put, Post y Elimine el Protocolo HTTP. En comparación con SOAP y XML-RPC complejos, los servicios web de modo REST son obviamente más concisos, y cada vez más servicios web están comenzando a adoptar el diseño e implementación de estilo REST. Por ejemplo, Amazon.com proporciona servicios web que están cerca del estilo de descanso para las búsquedas de libros; Los servicios web proporcionados por Yahoo también son estilo REST. El descanso no siempre es la elección correcta. Se ha vuelto popular como un método para diseñar servicios web que dependen menos en el middleware propietario, como un servidor de aplicaciones, que en los métodos basados en SOAP y WSDL. En cierto sentido, al enfatizar los estándares tempranos de Internet, como URI y HTTP, REST es una regresión al enfoque web antes de la era de los grandes servidores de aplicaciones.
Ejemplo como se muestra en la siguiente figura:
La clave para usar REST es cómo abstraer los recursos. Cuanto más precisa sea la abstracción, mejor será la aplicación de descanso.
Principios clave del servicio de descanso:
1. Dé una identificación a todos los objetos
2. Conecte objetos juntos
3. Use métodos estándar
4. Múltiples representaciones de recursos
5. Comunicación sin estado
Este artículo presenta cómo crear un marco de servicio de descanso simple basado en el arranque de primavera y cómo implementar la autenticación del servicio REST a través de anotaciones personalizadas
Construir un marco
pom.xml
Primero, introduzca dependencias relacionadas, use MongoDB para bases de datos y use Redis para caché
Nota: No se usa Tomcat aquí, sino una parada
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <MoupRoD> org.springframework.boot </groupid> <artifactid> spring-boot-starter-web </artifactid> <exclusions> <exclusion> <proupid> org.springframework.boot </groupid> <artifactid> spring-boot-starter-tomcat </artifactid> </exclusion> </exclusions> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency> <!--redis support--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <
Introducir servicios web de soporte de Spring-Boot-Starter-Web
La introducción de Data-Redis de Spring-Boot-Starter y Spring-Boot-Starter-Data-MongoDB puede usar fácilmente MongoDB y Redis
Archivo de configuración
Perfiles funcionan
Para facilitar la distinción entre el entorno de desarrollo y el entorno en línea, la función de perfiles se puede utilizar para agregarla en la aplicación.
spring.profiles.active=dev
Luego agregue la aplicación-dev.properties como el archivo de configuración de dev.
Configuración de MONDB
Simplemente configure la dirección de la base de datos
Spring.Data.MongoDB.uri = MongoDB: // IP: Port/Database? ReadPreference = PrimaryPreferred
Configuración de Redis
Spring.Redis.Database = 0 # Redis Servidor Dirección Spring.Redis.host = IP # Puerto de conexión del servidor Redis Spring.Redis.Port = 6379 # Redis Server Connection Password (predeterminado está vacío) Spring.Redis.Password = # Número máximo de conexiones en el grupo de conexiones (Usando valores negativos no tiene límite) Spring.Redis. spring.redis.pool.max-wait = -1 # Conexión inactiva máxima en el grupo de conexión Spring.redis.pool.max-idle = 8 # Conexión inactiva mínima en la conexión de conexión Spring.redis.pool.min-idle = 0 # Tiempo de espera de conexión (MS) Spring.Redis.TimeOut = 0 #
Acceso a datos
mongdb
El acceso a MongDB es muy simple. Puede definir directamente la interfaz extiende Mongorepository. Además, puede admitir la sintaxis JPA, por ejemplo:
@ComponentPublic Interface UserRepository extiende Mongorepository <User, Integer> {Public User findByUserName (String UserName);}Cuando lo use, simplemente agregue la anotación @aUtowired.
@ComponentPublic Class AuthService extiende BaseService {@aUtoWired UserRepository UserRepository; }Acceso a Redis
Use StringRedistEmplate para acceder a Redis directamente
@ComponentPublic Class BaseService {@aUtowired MongoTemplate MongoTemplate; @AUtowired stringRedIspplate stringRedIspplate stringRedistEmplate; }Datos de almacenamiento:
.StringredistEmplate.OpSforValue (). Set (token_key, user.getID ()+"", token_max_age, timeUnit.seconds);
Eliminar datos:
stringRedistEmplate.delete (getFormattoken (AccessToken, Plataforma));
Servicios web
Defina una clase de controlador, agregue RESTCONTROLLER y use RequestMapping para establecer la ruta de URL
@RestControllerPublic de la clase AuthController extiende BASECONTROLLER {@RequestMapping (value = {"/"}, produce = "Application/Json; Charset = UTF-8", Method = {requestmethod.get, requestmethod.post}) @ResponseBody String Main () {Hello World "; }}Ahora comienza, ¡deberías poder ver Hello World! Es
Autenticación de servicio
Mecanismo simple de acceso de acceso
Proporcione una interfaz de inicio de sesión. Después de que la autenticación es exitosa, se genera un acceso de acceso. Al acceder a la interfaz en el futuro, el AccessToken se trae consigo. El servidor utiliza el AccessToken para determinar si es un usuario legal.
Para mayor comodidad, puede salvar el acceso a Redis y establecer el período de validez.
String token = encryptionUtils.sha256hex (string.format ("%s%s", user.getusername (), system.currentTimemillis ())); Cadena token_key = getFormattoken (token, plataforma); this.StringredistEmplate.OpSforValue (). Set (token_key, user.getid ()+"", token_max_age, timeUnit.seconds);Autenticación de identidad de interceptor
Para facilitar la autenticación de identidad unificada, se puede crear un interceptor basado en el mecanismo de interceptor de Spring para realizar una autenticación unificada.
clase pública Authcheckinterceptor implementa HandlerInterceptor {}Para que el interceptor surtiera, se necesita un paso más para agregar configuración:
@ConfigurationPublic Class SessionConfiguration extiende WebMVCConfigurerAdapter {@aUtoWired AuthCheckInterceptor AuthCheckInterceptor; @Override public void addInterceptors (InterceptorRegistry Registry) {super.addinterceptors (registro); // Agregar Interceptor Registry.addinterceptor (AuthCheckInterceptor) .addPathPatterns ("/**"); }}Anotaciones de autenticación personalizadas
Para refinar la autenticación del permiso, por ejemplo, algunas interfaces solo pueden ser accedidas por personas con permisos específicos, y pueden resolverse fácilmente a través de anotaciones personalizadas. En la anotación personalizada, solo agregue roles.
/*** Anotación de verificación de permiso*/@Target (elementType.method) @Retention (retenciónPolicy.Runtime) @DocumentedPublic @Interface AuthCheck {/*** Lista de roles* @return*/String [] roles () predeterminado {};}Lógica de inspección:
Mientras la interfaz se agrega con la anotación AuthCheck, debe ser un usuario iniciado
Si se especifican los roles, además de iniciar sesión, el usuario también debe tener el papel correspondiente.
String [] ignoreUrls = new String [] {"/user/.*", "/cat/.*", "/app/.*", "/error"}; Public Boolean PreHandle (httpServletRequest httpservletRequest, httpServletResponse HttpServletResponse, Handler de objetos) lanza la excepción {// 0 Verifique los parámetros públicos if (! CheckParams ("Plataforma", httpservletRequest, httpServletResponse)) {return false; } // 1. Ignore la cadena de url de verificación url = httpservletRequest.getRequesturi (). ToString (); for (string ignoreUrl: ignoreUrls) {if (url.matches (ignoreUrl)) {return true; }} // 2. Anotación de verificación de consulta handlermethod handlermethod = (handlermethod) manejador; Método método = handlermethod.getMethod (); // consulta anotación authcheck authcheck = método.getAnnotation (authcheck.class); if (authCheck == null) {// sin anotación, sin retorno verdadero; } // 3. Si hay anotación, consulte AccessToken primero if (! CheckParams ("AccessToken", httpservletRequest, httpServletResponse)) {return false; } // verifique si el token expira entero userId = authservice.getuserIdFromToken (httpservletRequest.getParameter ("AccessToken"), httpservletRequest.getParameter ("Plataforma)); if (userId == null) {logger.debug ("accessToken") timeout "); outputs (resphipesult.builder.error (" accesstoken expirado "). build (), httpServletResponse); return false;} // 4. Recheck si los roles necesarios están incluidos si (authcheck.roles ()! = null && authcheck. Usuario = AuthService.getUser (UserID); Encapsulación del resultado de la respuesta del servicio
Agregue un constructor para facilitar la generación de resultados finales
Public Class ResponseSult {public static class Builder {ResponseSult ResponseSoUt; Map <string, object> datAMAP = maps.newhashmap (); Public Builder () {this.ResponseReSult = new ResponseSult (); } public Builder (string state) {this.esponseReSult = new ResponseSult (estado); } public static Builder newBuilder () {return new Builder (); } public static Builder Success () {return New Builder ("éxito"); } Error de Builder Public Static (mensaje de cadena) {Builder Builder = New Builder ("Error"); builder.esponseresult.setError (mensaje); Return Builder; } public Builder append (clave de cadena, datos del objeto) {this.datamap.put (clave, datos); devolver esto; } / *** Establezca datos de la lista* @param datos de datos* @return* / public Builder setListData (list <?> Datas) {this.datamap.put ("resultado", datas); this.datamap.put ("Total", DataS.Size ()); devolver esto; } public Builder setData (datos de objeto) {this.datamap.clear (); this.ResponseResult.setData (datos); devolver esto; } boolean wrapData = false; / ** * Wrap Data en datos * @param wrapdata * @return */ public builder wrap (boolean wrapData) {this.wrapData = wrapData; devolver esto; } public String Build () {jsonObject jsonObject = new jsonObject (); jsonObject.put ("estado", this.esponseresult.getState ()); if (this.ResponseReSult.getState (). Equals ("Error")) {jsonObject.put ("Error", this.ResponseReSult.getError ()); } if (this.ResponseReSult.getData ()! = NULL) {jsonObject.put ("data", json.tojson (this.ResponseReSult.getData ())); } else if (datAMAP.Size ()> 0) {if (wrapData) {jsonObject data = new jsonObject (); datamap.ForEach ((clave, valor) -> {data.put (clave, valor);}); jsonObject.put ("datos", datos); } else {datAMAP.FOREACH ((clave, valor) -> {jsonObject.put (clave, valor);}); }} return jsonObject.ToJSonstring (); }} estado de cadena privada; datos de objetos privados; error de cadena privada; public String getError () {Error de retorno; } public void setError (error de cadena) {this.error = error; } public ResponseSult () {} public ResponseSult (String rc) {this.state = rc; } / ** * return cuando exitosa * @param rc * @param result * / public respherseSult (string rc, resultado de objeto) {this.state = rc; this.data = resultado; } public String getState () {State de retorno; } public void setState (string state) {this.state = state; } Public Object getData () {return data; } public void setData (datos de objeto) {this.data = data; }} Ser más elegante al llamar
@RequestMapping (value = {"/user/login", "/pc/user/login"}, produce = "aplicación/json; charset = utf-8", método = {requestmethod.get, requestmethod.post}) @ResponseBody public String String (String UserNeNeN, String Password, plataforma) {User User = this.AuthServeRice. if (user! = null) {// Iniciar sesión en string token = authservice.updateToken (usuario, plataforma); return ResponseSult.Builder .Success () .Append ("AccessToken", Token) .Append ("UserId", user.getId ()) .Build (); } return ResponseSult.Builder.error ("El usuario no existe o la contraseña es incorrecta"). Build (); } Error de cadena protegido (mensaje de cadena) {return ResponseeSult.Builder.error (mensaje) .Build (); } string string protegido strace () {return ResponseSult.Builder .Success () .Build (); } Cadena protegida SuccessDatalist (list <?> data) {return ResponseSult.Builder .Success () .wrap (true) // data paquete.setListData (data) .Build (); }Resumir
Lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo tenga cierto valor de referencia para el estudio o el trabajo de todos. Si tiene alguna pregunta, puede dejar un mensaje para comunicarse. Gracias por su apoyo a Wulin.com.