Java基于ssm框架的restful应用开发

Java基于ssm框架的restful应用开发

好几年都没写过java的应用了,这里记录下使用java ssm框架、jwt如何进行rest应用开发,文中会涉及到全局异常拦截处理、jwt校验、token拦截器等内容。

1、jwt工具类

直接贴代码了,主要包括jwt的sign、verify、decode三个方法,具体实现如下:

package com.isoft.util;

import java.util.Date;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

public class JwtUtil {

    private static final String SECRET = "xxxxx";
    private static final String USERID = "userId";
    private static final String ISSUER = "xxxx.com";

    // 过期时间7天
    private static final long EXPIRE_TIME = 7 * 24 * 60 * 60 * 1000;

    // jwt sign
    public static String sign(Integer userId) {
        try {
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithmHS = Algorithm.HMAC256(SECRET);
            return JWT.create().withClaim(USERID, userId).withExpiresAt(date).withIssuer(ISSUER).sign(algorithmHS);
        } catch (Exception e) {
            return null;
        }
    }

    // jwt verify
    public static boolean verify(String token, Integer userId) {
        try {
            Algorithm algorithmHS = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithmHS).withClaim(USERID, userId).withIssuer(ISSUER).build();
            verifier.verify(token);
            return true;
        } catch (Exception e) {
            System.out.println(e);
            return false;
        }
    }

    // 返回token中的用户名
    public static Integer getUserId(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(USERID).asInt();
        } catch (Exception e) {
            return null;
        }
    }
}

2、全局异常处理类

ssm中进行rest全局异常拦截处理主要用到RestControllerAdvice型注解类,直接贴代码:

package com.isoft.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.isoft.po.Response;

@RestControllerAdvice
public class ExceptionAdvice {

    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Response handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        return new Response().failure("could not read json");
    }

    /**
     * 405 - Method Not Allowed
     * 
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Response handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        return new Response().failure("request method not supported");
    }

    /**
     * 500 - Internal Server Error
     * 
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)
    public Response handleException(Exception e) {
        System.err.println(e);
        return new Response().failure(e.getMessage());
    }
    
}

这里主要拦截了405、400、500的n行yi'chang异常情况,可根据具体情况拓展。

3、自定义Response返回类

我们自定义的Response返回类格式如下:

{
    "meta": {
        "success": true,
        "message": "ok"
    },
    data: Array or Object
}

代码如下:

package com.isoft.po;

public class Response {

    private static final String OK = "ok";
    private static final String ERROR = "error";

    private Meta meta;
    private Object data;

    public Response success() {
        this.meta = new Meta(true, OK);
        return this;
    }

    public Response success(Object data) {
        this.meta = new Meta(true, OK);
        this.data = data;
        return this;
    }
    
    public Response success(Object data, String msg){
        this.meta = new Meta(true, msg);
        this.data = data;
        return this;
    }
    
    public Response failure() {
        this.meta = new Meta(false, ERROR);
        return this;
    }

    public Response failure(String message) {
        this.meta = new Meta(false, message);
        return this;
    }

    public Meta getMeta() {
        return meta;
    }

    public Object getData() {
        return data;
    }

    public class Meta {

        private boolean success;
        private String message;

        public Meta(boolean success) {
            this.success = success;
        }

        public Meta(boolean success, String message) {
            this.success = success;
            this.message = message;
        }

        public boolean isSuccess() {
            return success;
        }

        public String getMessage() {
            return message;
        }
    }
}

4、jwt的token拦截器Interceptor

spring mvc的Interceptor实现类一般是继承HandlerInterceptor接口并重写preHandle、postHandle、afterCompletion的方法来实现的,这里我们直接进行token的verify返回即可,具体代码如下:

package com.isoft.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.isoft.util.JwtUtil;
import com.isoft.util.StringUtil;

/**
 * jwt token拦截
 * @author sd
 *
 */
public class TokenInterceptor implements HandlerInterceptor{

    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
        // TODO Auto-generated method stub
        
    }

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
        String token = req.getHeader("Authorization");
        if (StringUtil.isEmpty(token)) {
            return false;
        }
        token = token.replace("Bearer ", "");
        boolean isPass = JwtUtil.verify(token, JwtUtil.getUserId(token));
        if (isPass) {
            return true;
        }
        res.setStatus(401);
        return false;
    }
    
}

写完这些还不行,需要将拦截器注册到spring-mvc的config中:

<!-- mvc拦截器 -->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/users/login"/>
        <bean class="com.isoft.interceptor.TokenInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

这里使用mvc:exclude-mapping可以直接排除某个接口的拦截,比较方便。

5、mysql插入中文乱码解决

使用ssm框架mybatis进行数据插入时,发现插入中文进去后数据有乱码情况,除了设置数据库编码之外还解决不了问题的话,不妨看下mybatis的链接编码设置,如果是db.properties的话,使用如下设置:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://ip:port/dbname?useUnicode=true&characterEncoding=utf-8
jdbc.username=username
jdbc.password=password

6、一个简单的rest controller实例

package com.isoft.web.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.isoft.po.PageBean;
import com.isoft.po.Response;
import com.isoft.po.User;
import com.isoft.service.UserService;
import com.isoft.util.JwtUtil;
import com.isoft.util.StringUtil;

/**
 * 用户控制器类
 */

@RequestMapping("/users")
@RestController
public class UserController {

    @Resource
    private UserService userService;

    /**
     * 用户注册
     * 
     * @param user
     * @param res
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/", method = RequestMethod.POST)
    @ResponseStatus(value = HttpStatus.CREATED)
    public Response save(@RequestBody User user, HttpServletResponse res) throws Exception {
        userService.add(user);
        return new Response().success(user);
    }

    /**
     * 用户登录
     * 
     * @param user
     * @param res
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "login", method = RequestMethod.POST)
    @ResponseStatus(value = HttpStatus.OK)
    public Response login(@RequestBody User user, HttpServletResponse res) throws Exception {
        System.out.println(user);
        User u = userService.login(user);
        if (u != null) {
            String token = JwtUtil.sign(u.getId());
            u.setToken(token);
            u.setHashedPassword("");
            return new Response().success(u, "login success");
        }
        return new Response().failure("username or password wrong");
    }

    /**
     * 用户查询带分页
     * 
     * @param user
     * @param res
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    @ResponseStatus(value = HttpStatus.OK)
    public Response list(@RequestParam(value = "page", required = false, defaultValue = "1") String page,
            @RequestParam(value = "rows", required = false, defaultValue = "10") String rows, User s_user, HttpServletResponse res)
            throws Exception {
        System.out.println(s_user);
        PageBean pageBean = new PageBean(Integer.parseInt(page), Integer.parseInt(rows));
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("userName", StringUtil.formatLike(s_user.getUserName()));
        map.put("email", s_user.getemail());
        map.put("start", pageBean.getStart());
        map.put("size", pageBean.getPageSize());
        List<User> userList = userService.find(map);
        return new Response().success(userList);
    }
    
    /**
     * 用户更新
     * 
     * @param user
     * @param res
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    @ResponseStatus(value = HttpStatus.OK)
    public Response update(@PathVariable Integer id, @RequestBody User user, HttpServletResponse res) throws Exception {
        user.setId(id);
        System.out.println(user);
        Integer count = userService.update(user);
        if (count != 0) {
            return new Response().success();
        }
        return new Response().failure();
    }
    
    /**
     * 用户删除,支持批量
     * @param id
     * @param user
     * @param res
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/{ids}", method = RequestMethod.DELETE)
    @ResponseStatus(value = HttpStatus.OK)
    public Response delete(@PathVariable String ids, HttpServletResponse res) throws Exception {
        String[] idsStrings = ids.split(",");
        for (String id : idsStrings) {
            userService.delete(Integer.parseInt(id));
        }
        return new Response().success();
    }
    
    /**
     * 用户详情
     * @param id
     * @param user
     * @param res
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ResponseStatus(value = HttpStatus.OK)
    public Response getUser(@PathVariable Integer id, HttpServletResponse res) throws Exception {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("id", id);
        List<User> users = userService.find(map);
        return new Response().success(users);
    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏精讲JAVA

Java 8 和 Java 9 中并发工具的改变

Java 8 和 Java 9中 concurrent 包有了一些改变, 本文对这些改变做了汇总。

14620
来自专栏西安-晁州

Java基于ssm框架的restful应用开发

好几年都没写过java的应用了,这里记录下使用java ssm框架、jwt如何进行rest应用开发,文中会涉及到全局异常拦截处理、jwt校验、token拦截器等...

37060
来自专栏精讲JAVA

Java 8 和 Java 9 中并发工具的改变

Java 8 和 Java 9中 concurrent 包有了一些改变, 本文对这些改变做了汇总。

11420
来自专栏码匠的流水账

聊聊spring boot tomcat jdbc pool的属性绑定

本文主要研究一下spring boot tomcat jdbc pool的属性绑定

22320
来自专栏微服务那些事儿

微服务的异常处理

不加班的周末,整理了一下项目上的异常处理方案,和小伙伴们共享,里面不成熟的代码或解决方式.QAQ,评论区走起

1.4K60
来自专栏xiaoxi666的专栏

java8 Stream sorted()的一次调用链记录

看到结果不淡定了,因此决定调试一下看看内部包装了哪种排序算法,这一调试不得了,发现stream的调用链有点奇怪:

33710
来自专栏菩提树下的杨过

dubbox 增加google-gprc/protobuf支持

好久没写东西了,今年实在太忙,基本都在搞业务开发,晚上来补一篇,作为今年的收官博客。google-rpc 正式发布以来,受到了不少人的关注,这么知名的rpc框架...

1.4K80
来自专栏大内老A

谈谈WCF中的Data Contract(3):WCF Data Contract对Collection & Dictionary的支持

在本篇文章上一部分Order Processing的例子中,我们看到原本已Collection形式定义的DetailList属性(public IList<TD...

215100
来自专栏小白鼠

SpringBoot几个注解MockMvcWireMockSwagger2@JsonViewHibernate Validator异常处理拦截方式上传下载异步处理RESTSpring Security

只有特定名称或者类型的Bean(通过@ConditionalOnMissingBean修饰)不存在于BeanFactory中时才创建某个Bean

31830
来自专栏JavaEdge

@Autowired注解实现原理

74180

扫码关注云+社区

领取腾讯云代金券