模式的发展
最开始,在使用Servlet实现动态页面时,都要在Servlet中嵌入HTML代码输出显示,使得维护成本极大,为了解决这种问题就有了Jsp做页面输出,然而Jsp本质也是Servlet,所以不可避免的要写一些Java代码做脚本,为了不让Jsp内容混乱,就增加了标签,EL表达式来尽量代替Jsp中的Java代码。
MVC模式
模型(Model)
代表业务逻辑代码与数据库代码,通过JavaBean,传递存储数据。视图(View)
代表对数据的展示代码,用于显示模型中的数据,向控制器提交数据,如Jsp。控制器(Controller)
通常由Servlet充当控制器,连接着View和Model。
1. 从页面View中获得请求参数
2. 再从Model中通过业务逻辑代码获取需要的数据,通过Bean传递
3. 然后再交给View去显示,更新页面
下面通过一个简单的在A界面输入用户信息,传递给B界面显示,看一下MVC的工作流程。
Model
public class UserBean {
private String name;
public UserBean() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
View:界面A.jsp,用于输入用户名,发起请求
A
Controller:用于获取界面A中用户输入的用户名,将数据封装到JavaBean中,转发给显示界面。
@WebServlet(value = "/a")
public class AServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
UserBean userBean = new UserBean();
userBean.setName(req.getParameter("name"));
req.getSession().setAttribute("user",userBean);
resp.sendRedirect("show_user_info.jsp");
}
}
View:显示界面B.jsp,用于显示界面A传递过来的用户输入的名称
JSPDemo
提交的用户名为:
三层架构
Web层(表示层)
用于获取用户输入的参数,通知Service层处理数据,根据Service的返回结果,控制跳转页面展示数据。service层(业务逻辑层)
连接Web层与Dao层,根据Dao返回的数据库结果,设置数据返回给Web层的请求结果。dao层(数据访问层)
操作数据库的CRUD,将结果返回给Service。
用户注册邮箱激活代码流程
前置工作
domain用来传递用户数据
public class UserBean {
private String uid; //用户ID
private String username;
private String password;
private String name;
private String email;
private String telephone;
private Date birthday;
private String sex;
private int state; //账号激活状态
private String code; /
}
前台表单提交及校验
注意
控件的name最好和domain里面bean的名称一致
bean的属性名称和数据库的字段名称一致
使用jquery.validate.min.js进行前台校验
1. 通过表单id找到表单进行校验
2. 用ajax向后台请求查询数据库,用户数量,通过Json将数据返回给前台
1. 获取到用户输入的用户名
2. 调用UserService去查询数据库,Service会返回Boolean告知成功失败
3. 根据Service返回的Boolean将数据传递给前提
public class CheckUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String userName = req.getParameter("username");
UserService userService = new UserService();
boolean isExists = userService.checkUserExists(userName);
resp.getWriter().println("{\"isExists\":" + isExists + "}");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
调用UserDao去查询数据库,根据UserDao的返回值判断返回Boolean
public class UserService {
private UserDao userDao = new UserDao();
public boolean checkUserExists(String userName) {
Long aLong = 0L;
try {
aLong = userDao.checkUserExists(userName);
} catch (SQLException e) {
e.printStackTrace();
}
return aLong > 0 ? true : false;
}
}
查询数据库中的此用户数量,将结果返回给Service
public class UserDao {
public Long checkUserExists(String userName) throws SQLException {
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
String sql = "select count(*) from t_user where username = ?";
Long aLong = (Long) runner.query(sql,new ScalarHandler(),userName);
return aLong;
}
}
用户注册
Web层
注意
1. 封装Bean时birthday用的是Date数据,BeanUtils框架需要转换parse
public class RegisterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
Map parameters = req.getParameterMap();
UserBean userBean = new UserBean();
try {
//前面封装的Bean,日期是Date类型
//BeanUtils需要转换一下类型
ConvertUtils.register(new Converter() {
@Override
public Object convert(Class aClass, Object o) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
//额外注意
date = format.parse(o.toString());
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}, Date.class);
BeanUtils.populate(userBean, parameters);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
//将用户没传递的数据补全
userBean.setUid(CommonsUtils.getUUID());
userBean.setState(0);
String activeCode = CommonsUtils.getUUID();
userBean.setCode(activeCode);
//调用Service注册
UserService userService = new UserService();
boolean isRegisterSuccess = userService.registerUser(userBean);
if (isRegisterSuccess) {
try {
String emailMsg = "恭喜您注册成功,请点击激活账户" +
"" +
"http://localhost:8080/active?activeCode=" + activeCode +
"";
MailUtils.sendMail(userBean.getEmail(),emailMsg);
} catch (MessagingException e) {
e.printStackTrace();
}
resp.sendRedirect("/login.jsp");
} else {
resp.getWriter().println("注册失败");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
Service层
public class UserService {
private UserDao userDao = new UserDao();
public boolean registerUser(UserBean userBean) {
int row = 0;
try {
row = userDao.registerUser(userBean);
} catch (SQLException e) {
e.printStackTrace();
}
return row > 0 ? true : false;
}
}
Dao层
public class UserDao {
public int registerUser(UserBean userBean) throws SQLException {
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
String sql = "insert into t_user values(?,?,?,?,?,?,?,?,?,?)";
int row = runner.update(sql,
userBean.getUid(),
userBean.getUsername(),
userBean.getPassword(),
userBean.getName(),
userBean.getEmail(),
userBean.getTelephone(),
userBean.getBirthday(),
userBean.getSex(),
userBean.getState(),
userBean.getCode());
return row;
}
}
邮箱激活注册账号
注册成功后用Mail发送邮件,附带着请求激活地址,和UUID来做激活码。
所谓的邮箱账号激活,其实就是修改用户表中用户的state
public class MailUtils {
public static void sendMail(String email, String emailMsg)
throws AddressException, MessagingException {
// 1.创建一个程序与邮件服务器会话对象 Session
Properties props = new Properties();
props.setProperty("mail.transport.protocol", "SMTP");
props.setProperty("mail.host", "smtp.163.com"); //发邮件的服务器地址
props.setProperty("mail.smtp.auth", "true");//需要验证,不验证会提示没有权限发送
//指定验证为true
// 创建验证器
Authenticator auth = new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
//发送邮件的邮箱账户 + 授权码
return new PasswordAuthentication("133******53", "******");
}
};
Session session = Session.getInstance(props, auth);
// 2.创建一个Message,它相当于是邮件内容
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("133******[email protected]")); // 设置发送者
message.setRecipient(RecipientType.TO, new InternetAddress(email)); // 设置发送方式与接收者
message.setSubject("用户激活");
// message.setText("这是一封激活邮件,请点击");
message.setContent(emailMsg, "text/html;charset=utf-8");
// 3.创建 Transport用于将邮件发送
Transport.send(message);
}
}
@WebServlet(value = "/active")
public class ActiveServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html; charset=UTF-8");
String activeCode = req.getParameter("activeCode");
UserService userService = new UserService();
boolean isActiveUser = userService.activeUser(activeCode);
if (isActiveUser){
resp.sendRedirect("/login.jsp");
}else{
resp.getWriter().println("用户未激活");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req,resp);
}
}
Service层
public class UserService {
private UserDao userDao = new UserDao();
public boolean activeUser(String activeCode) {
int row = 0;
try {
row = userDao.activeUser(activeCode);
} catch (SQLException e) {
e.printStackTrace();
}
return row > 0 ? true : false;
}
}
Dao层
public class UserDao {
public int activeUser(String activeCode) throws SQLException {
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
String sql = "update t_user set state = ? where code = ?";
int update = runner.update(sql, 1, activeCode);
return update;
}
}