黑马旅游网编写练习(4)--优化工程目录结构
黑马旅游网编写练习(4)–优化工程目录结构
经过前面的三次练习,已经实现了用户的登录,账户**,以及用户退出的相关功能;然而在实际项目过程中,这些当然只能算是基础功能;在此过程中,我们为每一个小功能都独立创建了servlet资源;至此,观察一下我们的项目结构:
观察目录结构,可以知道,仅此用户相关的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
- Servlet 是包含访问服务器资源的整个生命周期,包括创建init,服务service以及销毁destroy方法。
- GenericeServlet是一个抽象类,它继承了Servlet,对servlet中的方法做了空实现,并且将service方法设为了抽象方法
- HttpServlet继承了GenericeServlet,并且在service方法中对http协议进行了封装,通过判断请求的方式,对不同请求去调用不同的方法;如post请求方式,则执行doPost方法。
BaseServlet抽取
明白了Servlet的体系结构之后,我们可以自己编写一个BaseServlet,重写其service方法,我们可以不通过请求方式来区分,我们可以根据其请求路径uri来区分,从uri中提取出请求方法,然后调用该方法。
比如我们编写一个UserServlet,让其继承BaseServlet;并设置其请求路径为/user/*;那么所有uri中包含user的都会访问此资源。比如有一请求资源为/travel/user/login,其中travel是项目路径,我们可以设置为BaseServlet的访问路径为;则就会访问此BaseServlet中的service方法,然后我们抽取出login,让其去调用我们编写的位于UserServlet中的login方法。访问结构目录如下所示:
接下来完成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目录结构如下:
下一篇: java学习第一天