JavaEE自定义MVC框架

发布于 2018-12-15  6 次阅读


java大作业老师不让使用框架,所以就自己用servlet实现了一些必要的功能。

At.java

package com.likole.homeworkmanager.servlet.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by likole on 12/10/18.
 */
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface At {
    String value() default "";
}

Controller.java

package com.likole.homeworkmanager.servlet.annotations;

import java.lang.annotation.*;

/**
 * Created by likole on 12/10/18.
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Controller {
    String value() default "";
}

DispatcherServlet.java

package com.likole.homeworkmanager.servlet;

import com.alibaba.fastjson.JSON;
import com.likole.homeworkmanager.servlet.annotations.At;
import com.likole.homeworkmanager.servlet.annotations.Controller;
import com.likole.homeworkmanager.utils.SecureUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;

/**
 * @author likole
 * @date 12/10/18
 */

@WebServlet("/api/*")
public class DispatcherServlet extends HttpServlet {

    private List<String> classNames = new ArrayList<>();
    private Map<String, Object> ioc = new HashMap<>();
    private Map<String, Method> handlerMapping = new HashMap<>();
    private Map<String, Object> controllerMap = new HashMap<>();

    @Override
    public void init() throws ServletException {
        doScanner("com.likole.homeworkmanager.controller");
        if (classNames.isEmpty()) {
            return;
        }
        for (String className : classNames) {
            try {
                Class<?> clazz = Class.forName(className);
                if (clazz.isAnnotationPresent(Controller.class)) {
                    String tmp = clazz.getSimpleName();
                    ioc.put(tmp.substring(0, 1).toLowerCase() + tmp.substring(1)+SecureUtils.getStringRandom(6), clazz.newInstance());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (ioc.isEmpty()) {
            return;
        }
        try {
            for (Map.Entry<String, Object> entry : ioc.entrySet()) {
                Class<? extends Object> clazz = entry.getValue().getClass();

                String baseUrl = "";
                if (clazz.isAnnotationPresent(At.class)) {
                    At annotation = clazz.getAnnotation(At.class);
                    baseUrl = annotation.value();
                }
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (!method.isAnnotationPresent(At.class)) {
                        continue;
                    }
                    At annotation = method.getAnnotation(At.class);
                    String url = annotation.value();

                    url = (baseUrl + "/" + url).replaceAll("/+", "/");
                    handlerMapping.put(url, method);
                    controllerMap.put(url, clazz.newInstance());
                    System.out.println(url + ":" + method);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 扫描包下的所有类
     */
    private void doScanner(String packageName) {
        URL url = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/"));
        File dir = new File(url.getFile());
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                doScanner(packageName + "." + file.getName());
            } else {
                String className = packageName + "." + file.getName().replace(".class", "");
                classNames.add(className);
            }
        }
    }


    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        req.setCharacterEncoding("utf-8");

        if (handlerMapping.isEmpty()) {
            return;
        }

        String url = req.getRequestURI();
        String contextPath = req.getContextPath();

        url = url.replace(contextPath, "").replace("/api", "").replaceAll("/+", "/");

        System.out.print(url+":");

        if (!this.handlerMapping.containsKey(url)) {
            System.out.println("404");
            resp.setStatus(404);
            return;
        }

        Method method = this.handlerMapping.get(url);
        System.out.println(method.getName());

        Class<?>[] parameterTypes = method.getParameterTypes();
        Map<String, String[]> parameterMap = req.getParameterMap();
        Object[] paramValues = new Object[parameterTypes.length];
        for (int i = 0; i < parameterTypes.length; i++) {
            String requestParam = parameterTypes[i].getSimpleName();
            if (requestParam.equals("HttpServletRequest")) {
                paramValues[i] = req;
                continue;
            }
            if (requestParam.equals("HttpServletResponse")) {
                paramValues[i] = resp;
                continue;
            }
            if(requestParam.equals("HttpSession")){
                paramValues[i]=req.getSession();
                continue;
            }
            if (requestParam.equals("String")) {
                for (Map.Entry<String, String[]> param : parameterMap.entrySet()) {
                    String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll(",\\s", ",");
                    paramValues[i] = value;
                }
            }
        }
        try {
            Object re= method.invoke(this.controllerMap.get(url), paramValues);
            if(re!=null){
                resp.setContentType("application/json;charset=UTF-8");
                resp.setCharacterEncoding("utf-8");
                PrintWriter printWriter=resp.getWriter();
                System.out.println(JSON.toJSON(re));
                printWriter.print(JSON.toJSON(re));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


}

BaseController.java

package com.likole.homeworkmanager.controller;

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

/**
 *
 * @author likole
 * @date 12/15/18
 */
public class BaseController {
    public Map<String,Object> error(String message){
        Map<String,Object> re=new HashMap<>();
        re.put("ok",false);
        re.put("message",message);
        return re;
    }

    public Map<String,Object> ok(){
        Map<String,Object> re=new HashMap<>();
        re.put("ok",true);
        return re;
    }

    public Map<String,Object> ok(String message){
        Map<String,Object> re=new HashMap<>();
        re.put("ok",true);
        re.put("message",message);
        return re;
    }
}

使用方法

控制类继承BaseController,并加上@Controller注解。

路径为类的@At注解加上方法的@At注解中的内容。

使用示例

package com.likole.homeworkmanager.controller;

import com.likole.homeworkmanager.dao.NotificationDao;
import com.likole.homeworkmanager.dao.UserDao;
import com.likole.homeworkmanager.servlet.annotations.At;
import com.likole.homeworkmanager.servlet.annotations.Controller;
import com.likole.homeworkmanager.entity.User;
import com.likole.homeworkmanager.utils.SecureUtils;
import com.likole.homeworkmanager.utils.MailUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;

/**
 * Created by likole on 12/10/18.
 */
@Controller
@At("/user")
public class UserController extends BaseController {

    private byte[] emailKEY = "yfHyN!5nyvtfMs9nF1P2QRkx".getBytes();

    @At("/register")
    public Object register(HttpServletRequest request, HttpServletResponse response, HttpSession session, String info) throws IOException, SQLException, NoSuchAlgorithmException {
        String username = request.getParameter("username");
        String email = request.getParameter("email");
        String password = request.getParameter("password");
        if ("".equals(email)) {
            return error("邮箱不能为空");
        }
        if ("".equals(username) || "".equals(password)) {
            return error("用户名或密码不能为空");
        }
        if (UserDao.getByUsername(username) != null) {
            return error("该用户名已被注册");
        }
        if (UserDao.getByEmail(email) != null) {
            return error("该邮箱已被注册");
        }
        User user=new User();
        user.setEmail(email);
        user.setUsername(username);
        user.setPassword(SecureUtils.getMD5(password));
        int newId = UserDao.add(user);
        session.setAttribute("user", UserDao.getByUid(newId));
        NotificationDao.add(-1,newId,"欢迎注册作业管理系统~");
        return ok();
    }

    @At("logout")
    public void logout(HttpSession session, HttpServletResponse response) throws IOException {
        session.invalidate();
        response.sendRedirect("/");
    }

    @At("login")
    public Object login(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws SQLException, NoSuchAlgorithmException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if ("".equals(username) || "".equals(password)) {
            return error("用户名或密码不能为空");
        }
        User user = UserDao.getByUsername(username);
        if (user != null && SecureUtils.getMD5(password).equals(user.getPassword())) {
            session.setAttribute("user",user);
            return ok();
        } else {
            return error("用户名或密码错误");
        }
    }

    @At("forgot")
    public Object forget(HttpServletRequest request) throws SQLException {
        String email = request.getParameter("email");
        if ("".equals(email)) {
            return error("邮箱不能为空");
        }
        User user = UserDao.getByEmail(email);
        if (user == null) {
           return error("该邮箱不存在");
        }
        //计算token
        String token=String.format("%s,%s,%s,%s",user.getUid(),user.getUsername(),user.getEmail(),System.currentTimeMillis());
        token = SecureUtils._3DES_encode(emailKEY, token.getBytes());
        //计算url
        String url=request.getRequestURL().toString();
        url=url.replace(request.getRequestURI(),"");
        url=url+request.getContextPath()+"/reset.jsp?token="+token;
        //发送邮件
        MailUtils.sendMail(user.getEmail(),"重置链接:"+url);
        return ok();
    }

    @At("reset")
    public Object reset(HttpServletRequest request){
        String token=request.getParameter("token");
        if("".equals(token)){
            return error("请不要直接访问这个链接!!!");
        }
        if (token.length() < 10) {
            return error("非法token");
        }
        try {
            token = SecureUtils._3DES_decode(emailKEY, SecureUtils.hexstr2bytearray(token));
            if (token == null) {
                return error("非法token");
            }
            String[] tmp = token.split(",", 4);
            if (tmp.length != 4 || tmp[0].length() == 0 || tmp[1].length() == 0 || tmp[2].length() == 0||tmp[3].length()==0) {
                return error("非法token");
            }
            long time = Long.parseLong(tmp[3]);
            if (System.currentTimeMillis() - time > 10*60*1000) {
                return error("该重置链接已经超时");
            }
            int uid = Integer.parseInt(tmp[0]);
            User user=UserDao.getByUid(uid);
            if(user==null) {
                return error("用户不存在");
            }
            if(tmp[1].equals(user.getUsername())&&tmp[2].equals(user.getEmail())){
                String password=SecureUtils.getStringRandom(6);
                UserDao.updatePassword(uid,SecureUtils.getMD5(password));
                NotificationDao.add(-1,uid,"密码已重置,请及时修改");
                return ok(password);
            }else{
                return error("验证失败!!请重新验证!!");
            }
        } catch (Throwable e) {
            return error("非法token");
        }
    }

    @At("/changePassword")
    public Object changePassword(HttpServletRequest request,HttpSession session) throws NoSuchAlgorithmException, SQLException {
        String oldPassword=request.getParameter("oldPassword");
        String password=request.getParameter("password");
        User user= (User) session.getAttribute("user");
        if("".equals(oldPassword)||"".equals(password)){
            return error("用户名不能为空");
        }
        if(!user.getPassword().equals(SecureUtils.getMD5(oldPassword))){
            return error("原密码错误");
        }
        UserDao.updatePassword(user.getUid(),SecureUtils.getMD5(password));
        return ok();
    }

    @At("/update")
    public Object updateEmailAndName(HttpServletRequest request,HttpSession session) throws SQLException, IOException {
        String email=request.getParameter("email");
        String name=request.getParameter("name");
        if(email==null||"".equals(email)){
            return error("邮箱不能为空");
        }
        User user= (User) session.getAttribute("user");
        User exists=UserDao.getByEmail(email);
        if(exists!=null&&exists.getUid()!=user.getUid()){
            return error("该邮箱已存在");
        }
        UserDao.updateEmailByUid(email,user.getUid());
        UserDao.updateNameByUid(name,user.getUid());
        session.setAttribute("user",UserDao.getByUid(user.getUid()));
        return ok();
    }
}

参考文章:https://blog.csdn.net/jackfrued/article/details/42774459