这个项目是我刚刚学完servlet 基础完成的一个练手小项目,花了有一星期左右完成了,前端html是完成的差不多的,我主要完 成的后端业务逻辑,这里都基本容易理解。总体感觉难点在前端分页查询显示的问题上,还有字符串拼接的小错误,实在难以察觉。
1. 下图是后端基于servlet 的代码结构
理解:完成项目,感受到了包结构实在是太重要了,井然有条的结构会让你有一条明确清晰的思路,完成项目代码编写工作。
除了包结构外,servlet类结构对于处理前端请求也很重要,例如 在 servlet 下 BaseServlet 里 用了反射,处理前端不同业务类型的请求,根据请求类型不同,用不同类型的类继承BaseServlet处理,这在后面会细说。
项目管理使用的是maven,这没啥好说的,很方便
旅游网后端事务:用户注册,登录,旅游项目分页查询,收藏,首页数据展示
*为了便于前端交互,后端代码编写,进行事务处理,使用父类servlet采用反射
//BaseServlet类
public class BaseServlet extends HttpServlet {
//service 每次客户端请求时,会自动调用这个方法,BaseServlet继承了httpservlet 并重写了service
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//完成方法分发
//1.获取请求路径
String uri = req.getRequestURI();
//2.获取方法名称
String methodName = uri.substring(uri.lastIndexOf('/') + 1);
//3.获取方法对象method
//谁调用我?我代表谁
// System.out.println(this);
try {
Method method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
//4.执行方法
//暴力反射
//method.setAcessible(true);
method.invoke(this, req, resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public void writeValue(Object obj, HttpServletResponse response) throws IOException {
// ObjectMapper mapper = new ObjectMapper();
// String json = mapper.writeValueAsString(obj);
// System.out.println("json:" + json);
// response.setContentType("application/json;charset=utf-8");
// response.getWriter().write(json);
ObjectMapper mapper = new ObjectMapper();
response.setContentType("application/json;charset=utf-8");
mapper.writeValue(response.getOutputStream(),obj);
}
/**
* 将传入的对象序列化为json,返回
*
* @param obj
* @return
*/
public String writeValueAsString(Object obj) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(obj);
}
}
BaseServlet反射原理:因为浏览器每次向服务器请求时,就会调用service方法,(重写过service 他就不会执行doPost 和doGet方法了)所以重写这个方法,在方法体内可以进行请求的分发。为方便代码编写,可以将重复出现的代码
1.用户功能
*注册思路,UserServlet类处理前端请求,调用 regist 注册方法 ,封装成User类,UserServiceImpl类处理业务,调用UserDaoImpl类向数据库写入用户,返回结果给ServiceImpl,其在返回给UserServlet,然后在将结果响应给前端。
//UserServlet类
@WebServlet("/user/*")
public class UserServlet extends BaseServlet {
//声明UserService业务对象
private UserService service = new UserServiceImpl();
/**
* 注册功能
* @param request
* @param response
* @throws IOException
*/
public void regist(HttpServletRequest request,HttpServletResponse response) throws IOException {
String check = request.getParameter("check");
HttpSession session = request.getSession();
String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
if (checkcode_server == null || !checkcode_server.equalsIgnoreCase(check)){
//验证码错误
ResultInfo info = new ResultInfo();
//注册失败
info.setFlag(false);
info.setErrorMsg("验证码错误");
// 序列化-----------------------
//将info对象序列化为json
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(info);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(json);
return;
}
//1.获取数据
Map<String, String[]> map = request.getParameterMap();
//2.封装对象
User user = new User();
try{
BeanUtils.populate(user,map);
//已经完成
}catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//3.调用service完成注册
UserServiceImpl service = new UserServiceImpl();
boolean flag = service.regist(user);
ResultInfo info = new ResultInfo();
//4.响应结果
if (flag){
info.setFlag(true);
}else {
//注册失败
info.setFlag(false);
info.setErrorMsg("注册失败!");
}
writeValue(info,response);
}
//------------------------------------------------------------------------------------------------
//UserService类
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public boolean regist(User user) {
//1.根据用户名查询用户对象
User u = userDao.findByUsername(user.getUsername());
//判断是否为null
if (u != null) {
//用户名存在,注册失败
return false;
}
//2.保存用户信息
//2.1设置激活码,唯一字符串
user.setCode(UuidUtil.getUuid());
//2.2设置激活状态
user.setStatus("N");
//3.激活邮件发送,邮件正文?
String content = "点击激活";
MailUtils.sendMail(user.getEmail(), content, "激活邮件");
userDao.save(user);
return true;
}
@Override
public boolean active(String code) {
User user = userDao.findByCode(code);
if (user!=null){
userDao.updateStatus(user);
return true;
}else {
return false;
}
}
}
//-----------------------------------------------------------------------------------
//UserDaoImpl类
//查找用户名是否存在
@Override
public User findByUsername(String username) {
User user = null;
try {
//1.定义sql语句
String sql = "select * from tab_user where username = ?";
//2.执行sql语句
user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username);
} catch (Exception e) {
e.printStackTrace();
}
return user;
}
//注册用户保存
@Override
public void save(User user) {
//1.定义sql语句
String sql = "insert into tab_user(username,password,name,birthday,sex,telephone,email,status,code) values(?,?,?,?,?,?,?,?,?)";
//2.查询
template.update(sql, user.getUsername(),
user.getPassword(),
user.getName(),
user.getBirthday(),
user.getSex(),
user.getTelephone(),
user.getEmail(),
user.getStatus(),
user.getCode()
);
}
}
*激活思路,注册时在User时用UuidUtil类写入随机字符串,使用MailUtils类发送邮箱给用户邮箱地址,链接为激活链接拼接User对应的随机字符串,用户点击时,UserServlet类处理请求,调用 active 激活方法 ,获取随机字符串,然后调用UserServiceImpl类,调用UserDaoImpl类查找随机串,对应的User在返回给UserServiceImpl,将状态修改为激活,返回布尔值给UserServlet ,其再将结果返回给前端。
//UserServlet类
/**
* 激活功能
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
public void active(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取激活码
String code = request.getParameter("code");
if(code != null){
//2.调用service完成激活
//UserService service = new UserServiceImpl();
boolean flag = service.active(code);
//3.判断标记
String msg = null;
if(flag){
//激活成功
msg = "激活成功,请登录";
}else{
//激活失败
msg = "激活失败,请联系管理员!";
}
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(msg);
}
}
}
//
//查找随机字符串
@Override
public User findByCode(String code) {
User user = null;
try {
String sql = "select * from tab_user where code = ?";
user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), code);
} catch (Exception e) {
e.printStackTrace();
}
return user;
}
用户登录思路,依照上面的处理请求方式,可以得出都是前端到数据库,然后结果返回到前端的过程,那就是封装好User,通过账号和密码查询数据库是否存在用户,结果返回给前端即可
public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取用户名的密码数据
Map<String, String[]> map = request.getParameterMap();
//2.封装User对象
User user = new User();
try {
BeanUtils.populate(user, map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//3.调用Service查询
UserServiceImpl service = new UserServiceImpl();
User u = service.login(user);
// System.out.println(u.getUsername()+":"+u.getPassword());
ResultInfo info = new ResultInfo();
//4.判断用户对象是否为null
if (u == null) {
//用户名密码或错误
info.setFlag(false);
info.setErrorMsg("用户名或密码错误");
}
//5.判断用户是否激活
if (u != null && !"Y".equals(u.getStatus())) {
//用户尚未激活
info.setFlag(false);
info.setErrorMsg("您尚未激活,请激活");
}
//6.判断登录成功
if (u != null && "Y".equals(u.getStatus())) {
request.getSession().setAttribute("user", u);
//登录成功
info.setFlag(true);
}
writeValue(info,response);
}
//--------------------------------------------------------------------------------
//UserServiceImpl类
@Override
public User login(User user) {
return userDao.findByUsernameAndPassword(user.getUsername(),user.getPassword());
}
//-------------------------------------------------------------------------------------
//UserDaoImpl类
@Override
public User findByUsernameAndPassword(String username, String password) {
User user = null;
try{
//1.定义sql 原sql只能找出账号密码同时正确的账号
String sql = " select * from tab_user where username = ? and password = ?";
//2.执行sql
user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username, password);
//解释 template 他会封装sql语句查询到的结果 但没查到的时候他会抛出异常,所以这里要try
}catch (Exception e){
e.printStackTrace();
}
return user;
}
好的至此用户相关的交互就差不多这些了,主要的是旅游项目线路处理。
我将写在下一篇文章中