欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

黑马旅游网编写练习(4)--优化工程目录结构

程序员文章站 2022-03-06 08:19:56
...

黑马旅游网编写练习(4)–优化工程目录结构

经过前面的三次练习,已经实现了用户的登录,账户**,以及用户退出的相关功能;然而在实际项目过程中,这些当然只能算是基础功能;在此过程中,我们为每一个小功能都独立创建了servlet资源;至此,观察一下我们的项目结构:
黑马旅游网编写练习(4)--优化工程目录结构

观察目录结构,可以知道,仅此用户相关的servlet就有好几个文件。如果再添加了其他的与用户无关的其他功能,则文件可能会更多,到时非常不利于维护;然而观察service以及dao层;该层均是只有一个接口文件,以及一个实现类文件;项目结构一目了然,我们能否仿照这个结构来管理servlet呢?
首先来观察service层;我们只需要查看UserService接口文件,便可以知道service层做了哪些工作,并且十分简洁;如下所示:

    public interface UserService {

    /**
     * 通过用户名查询数据库
     * @param username
     * @return  Boolean 若该用户已存在,则返回该对象
     */
    public Boolean findUserByName(String username);

    /**
     * 注册用户,注册成功返回true
     * @param user
     * @return
     */
    public Boolean regist(User user);

    /**
     * 通过**码给用户进行**,**成功返回true
     * @param code
     * @return
     */
    public Boolean active(String code);

    /**
     * 通过用户名和密码登录,登陆成功返回user
     * @param user
     * @return
     */
    public User login(User user);
}

想要查看某个方法的具体编写,再去该接口的实现类中去查找即可;非常的清晰,也非常方便;比servlet层多个文件要好上很多;所以我们也借鉴此方法,将servlet层进行相关管理。
通过观察各servlet文件,我们知道均需要继承HttpServlet,然后由于请求方法大多数都是post和get,所以只需要对这两个请求进行编写即可。我们再回顾一下servlet的体系结构

Servlet的体系结构
* Servlet
|
* GenericeServlet
|
* HttpServlet

  1. Servlet 是包含访问服务器资源的整个生命周期,包括创建init,服务service以及销毁destroy方法。
  2. GenericeServlet是一个抽象类,它继承了Servlet,对servlet中的方法做了空实现,并且将service方法设为了抽象方法
  3. HttpServlet继承了GenericeServlet,并且在service方法中对http协议进行了封装,通过判断请求的方式,对不同请求去调用不同的方法;如post请求方式,则执行doPost方法。
    黑马旅游网编写练习(4)--优化工程目录结构

BaseServlet抽取
明白了Servlet的体系结构之后,我们可以自己编写一个BaseServlet,重写其service方法,我们可以不通过请求方式来区分,我们可以根据其请求路径uri来区分,从uri中提取出请求方法,然后调用该方法。
比如我们编写一个UserServlet,让其继承BaseServlet;并设置其请求路径为/user/*;那么所有uri中包含user的都会访问此资源。比如有一请求资源为/travel/user/login,其中travel是项目路径,我们可以设置为BaseServlet的访问路径为;则就会访问此BaseServlet中的service方法,然后我们抽取出login,让其去调用我们编写的位于UserServlet中的login方法。访问结构目录如下所示:
黑马旅游网编写练习(4)--优化工程目录结构
接下来完成BaseServlet的编写:

    /**
     * 抽取方法,根据uri完成对不同方法的调用
     */
    public class BaseServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 获取请求路径uri
            String uri = req.getRequestURI();
            System.out.println(uri);
    
            // 抽取方法名称   /travel/user/login
            String methodName = uri.substring(uri.lastIndexOf('/') + 1);
            System.out.println(methodName);
    
            try {
                // 获取方法对象 Method
                // 谁调用了此service方法,this即代表谁
                System.out.println(this);
    
                Method method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
                // 执行该方法
                method.invoke(this,req,resp);
    
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

编写完成BaseServlet后,我们可以编写一个UserServlet类,来继承此BaseServlet;在UserServlet类中完成与用户相关的方法,例如用户登陆方法,我们可以将之前写好的LoginServlet中的代码粘贴到UserServlet类中,并起名为login方法。同样的操作,他其他的Servlet中内容复制到此类中;分别对应不同的方法;同时修改前端的访问路径。编写完毕之后,由于很多操作都是重复的,所以我们将其抽取为独立的方法,比如json序列化方法,验证码校验方法等,将这些方法写在BaseServlet中。
抽取的方法如下:

    // 序列化json的对象
    private ObjectMapper mapper = new ObjectMapper();
    // 创建错误信息对象
    private ResultInfo info =new ResultInfo();
    
    /**
     * 判断客户端输入的验证码是否正确,若错误,自动封装错误数据,并返回给客户端
     * @param request
     * @return
     */
    public Boolean checkCheckCode(HttpServletRequest request,HttpServletResponse response) throws IOException {
        // 接收验证码
        String check = request.getParameter("check");
        // 获取session域中的验证码信息
        HttpSession session = request.getSession();
        String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
        // 获取完毕即刻清楚session域中的验证码信息,以保证一次性使用
        session.removeAttribute("CHECKCODE_SERVER");

        // 判断输入的验证码是否正确
        if(!("".equals(check)) && check.equalsIgnoreCase(checkcode_server)){
            // 验证码正确
            System.out.println("The CheckCode input correct");
            return true;
        }else{
            // 验证码输入错误
            System.out.println("The CheckCode input Errors");
            info.setFlag(false);
            info.setData("checkcode");
            info.setErrorMsg("The CheckCode input Errors!");
            // 序列化错误信息为json,并响应给客户端
            responseJson(response,info);
            return false;
        }
    }

    /**
     * 将错误信息对象序列化为json数据,并响应给客户端
     * @param response
     * @param info
     * @throws IOException
     */
    public void responseJson(HttpServletResponse response, ResultInfo info) throws IOException {
        // 序列化info为json
        String json = mapper.writeValueAsString(info);
        System.out.println(json);

        // 将json数据发送给客户端
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(json);
    }

    /**
     * 接收表单的数据,并将其封装到user对象,返回user对象
     * @param request
     * @return
     */
    public User receiveDataToUser(HttpServletRequest request){
        // 接收表单数据
        Map<String, String[]> map = request.getParameterMap();

        // 封装数据到user对象
        User user = new User();
        try {
            BeanUtils.populate(user,map);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return user;
    }

使用上述抽取的方法,对UserServlet进行简化,精简后代码如下:

    @WebServlet("/user/*")
    public class UserServlet extends BaseServlet {
    
        // 创建UserService对象
        private UserService service = new UserServiceImpl();
        // 创建错误信息对象
        private ResultInfo info =new ResultInfo();
        
        /**
         * 注册用户方法
         * @param request
         * @param response
         * @throws ServletException
         * @throws IOException
         */
        public void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            // 判断验证码是否正确
            Boolean flag = checkCheckCode(request,response);
            if(!flag){
                // 验证码输入错误,结束
                return;
            }
    
            // 接收表单数据,到User对象
            User user = receiveDataToUser(request);
    
            // 调用service层完成注册
            boolean reg_flag = service.regist(user);
            if(reg_flag){
                // 注册成功
                System.out.println("Registered Succeed!");
                info.setFlag(true);
    
            }else{
                //注册失败
                System.out.println("Registered Faild!");
                info.setFlag(false);
                info.setData("regist");
                info.setErrorMsg("Registered Faild!");
            }
    
            // 序列化错误信息为json,并响应给客户端
            responseJson(response,info);
    
        }
    
        /**
         * 查询该用户名是否已存在
         * @param request
         * @param response
         * @throws ServletException
         * @throws IOException
         */
        public void findUser(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //获取用户名
            String username = request.getParameter("username");
            System.out.println(username);
            //调用service层的方法检验用户名是否存在
            UserService service = new UserServiceImpl();
            Boolean isExist = service.findUserByName(username);
    
            //判断是否存在,封装到json数据中
            if (isExist){
                // 用户名已被使用
                info.setFlag(true);
                info.setErrorMsg("The username has been Used!");
    
            }else {
                // 用户名未被使用
                info.setFlag(false);
            }
            // 序列化错误信息为json,并响应给客户端
           responseJson(response,info);
    
        }
    
    
        /**
         * **用户方法
         * @param request
         * @param response
         * @throws ServletException
         * @throws IOException
         */
        public void activeUser(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //接收用户的**码
            String code = request.getParameter("code");
            System.out.println("code:"+code);
            if(code == null || code.length() <= 0){
                // **码不存在
                return;
            }
    
            //调用service层方法,完成邮箱的**
            Boolean activated = service.active(code);
    
            String msg = null;
            if(activated){
                // **成功
                System.out.println("Active succeed!");
                msg = "**成功,请<a href='../login.html'>登录</a>";
            }else{
                //**失败
                System.out.println("Active failed!");
                msg = "**失败,请重新**";
            }
    
            //将消息发送给客户端
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().write(msg);
        }
    
        /**
         * 用户登陆方法
         * @param request
         * @param response
         * @throws ServletException
         * @throws IOException
         */
        public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            // 判断验证码是否正确
            Boolean flag = checkCheckCode(request,response);
            if(!flag){
                // 验证码输入错误,结束
                return;
            }
    
            // 接收表单数据,到User对象
            User user = receiveDataToUser(request);
    
            // 调用service层进行登录
            User u = service.login(user);
    
            // 判断是否登录成功
            if(u == null){
                // 登录失败,用户名或密码错误
                System.out.println("Login failed!, Username or Password Error!");
                info.setFlag(false);
                info.setErrorMsg("Login failed!, Username or Password Error!");
            }else if(u != null && "N".equals(u.getStatus())){
                // 登陆失败,用户未**
                System.out.println("Login failed!, User have No Active!");
                info.setFlag(false);
                info.setErrorMsg("Login failed!, User have No Active!");
            }else if(u != null && "Y".equals(u.getStatus())){
                // 登陆成功
                request.getSession().setAttribute("user",u);
                System.out.println("Login succeed!");
                info.setFlag(true);
            }
    
            // 序列化错误信息为json,并响应给客户端
            responseJson(response,info);
    
        }
    
        /**
         * 欢迎用户登陆成功方法
         * @param request
         * @param response
         * @throws ServletException
         * @throws IOException
         */
        public void helloUser(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 获取session域中的user对象
            HttpSession session = request.getSession();
            User user = (User) session.getAttribute("user");
    
            // 将user进行json序列化,并返回客户端
            response.setContentType("application/json;charset=utf-8");
            ObjectMapper mapper = new ObjectMapper();
            mapper.writeValue(response.getOutputStream(),user);
        }
    
        /**
         * 用户退出登录方法
         * @param request
         * @param response
         * @throws ServletException
         * @throws IOException
         */
        public void exitUser(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //获取session并销毁session域中数据
            request.getSession().invalidate();
    
            // 重定向到登陆页面
            response.sendRedirect(request.getContextPath()+"/login.html");
        }
    
    }

至此,项目的优化已经完成了,与用户相关的服务均位于UserServlet中;当然前台的一些访问路径也与要相应的进行更改;修改后的Servlet目录结构如下:
黑马旅游网编写练习(4)--优化工程目录结构

相关标签: java-web综合练习