网上商城(OnlineMall)用户模块
create database onlinemall; use onlinemall; CREATE TABLE `user` ( `uid` varchar(100) NOT NULL, `username` varchar(20) DEFAULT NULL, `password` varchar(20) DEFAULT NULL, `name` varchar(20) DEFAULT NULL, `email` varchar(30) DEFAULT NULL, `telephone` varchar(20) DEFAULT NULL, `birthday` date DEFAULT NULL, `sex` varchar(10) DEFAULT NULL, `state` int(11) DEFAULT NULL, `code` varchar(100) DEFAULT NULL, PRIMARY KEY (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
com.web.servlet com.web.filter com.iservice com.service.impl com.dao com.dao.impl com.bean com.utils com.constant
package com.web.servlet; import java.io.IOException; import java.lang.reflect.Method; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 为了提高代码的复用性,我们写了这个基类, * * @author LuoJoy * */ public class BaseServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 使用反射技术获取方法,并调用方法 // 获取隐藏域传过来的method String methodName = request.getParameter("method"); // 获取字节码文件对象 Class<? extends BaseServlet> clazz = this.getClass(); try { Method method = clazz.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); String path = (String) method.invoke(this, request, response); // 不等于null时说明都是需要执行请求转发,因为如果时请求重定向,那么就让它返回空,这样就不会执行下面的代码,而是执行原来的方法 if (path != null) { request.getRequestDispatcher(path).forward(request, response); } } catch (Exception e) { e.printStackTrace(); } } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
package com.web.filter; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; /** * 统一编码 * @author Administrator * */ public class EncodingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { //1.强转 HttpServletRequest request=(HttpServletRequest) req; HttpServletResponse response=(HttpServletResponse) resp; //2.放行 chain.doFilter(new MyRequest(request), response); } @Override public void destroy() { // TODO Auto-generated method stub } } class MyRequest extends HttpServletRequestWrapper{ private HttpServletRequest request; private boolean flag=true; public MyRequest(HttpServletRequest request) { super(request); this.request=request; } @Override public String getParameter(String name) { if(name==null || name.trim().length()==0){ return null; } String[] values = getParameterValues(name); if(values==null || values.length==0){ return null; } return values[0]; } @Override /** * hobby=[eat,drink] */ public String[] getParameterValues(String name) { if(name==null || name.trim().length()==0){ return null; } Map<String, String[]> map = getParameterMap(); if(map==null || map.size()==0){ return null; } return map.get(name); } @Override /** * map{ username=[tom],password=[123],hobby=[eat,drink]} */ public Map<String,String[]> getParameterMap() { /** * 首先判断请求方式 * 若为post request.setchar...(utf-8) * 若为get 将map中的值遍历编码就可以了 */ String method = request.getMethod(); if("post".equalsIgnoreCase(method)){ try { request.setCharacterEncoding("utf-8"); return request.getParameterMap(); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else if("get".equalsIgnoreCase(method)){ Map<String,String[]> map = request.getParameterMap(); if(flag){ for (String key:map.keySet()) { String[] arr = map.get(key); //继续遍历数组 for(int i=0;i<arr.length;i++){ //编码 try { arr[i]=new String(arr[i].getBytes("iso8859-1"),"utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } flag=false; } //需要遍历map 修改value的每一个数据的编码 return map; } return super.getParameterMap(); } }
事务管理工具类
package com.utils; import java.beans.PropertyVetoException; import java.sql.Connection; import java.sql.SQLException; public class TransactionManager { private static ThreadLocal<Connection> local = new ThreadLocal<>(); public static Connection getConnectionFromThreadLocal() throws Exception{ Connection conn = local.get(); //判断conn是否为null if (conn == null) { conn = C3P0Util.getConnection(); //存到local中去 local.set(conn); } return conn; } /** * 开启事务 * @throws PropertyVetoException * @throws SQLException */ public static void startTransaction() throws Exception{ getConnectionFromThreadLocal().setAutoCommit(false); } /** * 提交事务 */ public static void commit() throws Exception{ getConnectionFromThreadLocal().commit(); } /** * 回滚事务 * @throws Exception */ public static void rollback() throws Exception{ getConnectionFromThreadLocal().rollback(); } /** * 关闭连接 * @throws Exception */ public static void close() throws Exception{ getConnectionFromThreadLocal().close(); //连接关闭之后,将该连接从ThreadLocal中移除掉 local.remove(); } }
生成uid的工具类
package com.utils; import java.util.UUID; public class UUIDUtils { /** * 随机生成id * @return */ public static String getId(){ return UUID.randomUUID().toString().replace("-", "").toUpperCase(); } }
邮件发送工具类
package com.utils; import java.util.Properties; import javax.mail.Authenticator; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMessage.RecipientType; public class MailUtils { /** * @param email 收件人地址 * @param emailMsg 邮件内容 * @param subject 邮件主题 * @throws AddressException * @throws MessagingException */ public static void sendMail(String email, String emailMsg,String subject) throws AddressException, MessagingException { // 1.创建一个程序与邮件服务器会话对象 Session Properties props = new Properties(); //设置发送的协议 props.setProperty("mail.transport.protocol", "SMTP"); //设置发送邮件的服务器---->需要改成自己的发送邮件的服务器地址 props.setProperty("mail.host", "localhost"); props.setProperty("mail.smtp.auth", "true");// 指定验证为true // 创建验证器 Authenticator auth = new Authenticator() { public PasswordAuthentication getPasswordAuthentication() { //设置发送人的帐号和密码---->设置成本公司的邮箱账号 return new PasswordAuthentication("service@store.com", "123456"); } }; Session session = Session.getInstance(props, auth); // 2.创建一个Message,它相当于是邮件内容 Message message = new MimeMessage(session); //设置发送者 message.setFrom(new InternetAddress("service@store.com")); //设置发送方式与接收者 message.setRecipient(RecipientType.TO, new InternetAddress(email)); //设置邮件主题 message.setSubject(subject); // message.setText("这是一封激活邮件,请<a href='#'>点击</a>"); //设置邮件内容 message.setContent(emailMsg, "text/html;charset=utf-8"); // 3.创建 Transport用于将邮件发送 Transport.send(message); } }
C3P0工具类
package com.utils; import java.beans.PropertyVetoException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class C3P0Util { private static ComboPooledDataSource dataSource; static{ //从C3P0连接池中获取连接对象 dataSource = new ComboPooledDataSource(); } /** * 获得连接对象 * @return * @throws SQLException * @throws PropertyVetoException */ public static Connection getConnection() throws SQLException, PropertyVetoException{ return dataSource.getConnection(); } public static void close(ResultSet resultSet,Statement statement,Connection connection) throws SQLException{ if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } /** * 获得连接池对象 * @return */ public static DataSource getDataSource(){ return dataSource; } }
c3p0配置文件
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <default-config> <property name="checkoutTimeout">30000</property> <property name="initialPoolSize">10</property> <property name="maxPoolSize">100</property> <property name="minPoolSize">10</property> <property name="user">root</property> <property name="password">123</property> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/onlinemall</property> </default-config> </c3p0-config>
/**
* 1 首先什么是面向接口编程?
*
* 面向接口编程就是先把客户的业务逻辑线提取出来,作为接口,业务具体实现通过该接口的实现类来完成。
* 当客户需求变化时,只需编写该业务逻辑的新的实现类,通过更改配置文件(例如Spring框架)中该接口
* 的实现类就可以完成需求,不需要改写现有代码,减少对系统的影响
*
* 面向接口编程的优点?
* 1 降低程序的耦合性。其能够最大限度的解耦,所谓解耦既是解耦合的意思,它和耦合相对。耦合就是联系
* ,耦合越强,联系越紧密。在程序中紧密的联系并不是一件好的事情,因为两种事物之间联系越紧密,你更换
* 其中之一的难度就越大,扩展功能和debug的难度也就越大。
* 2 易于程序的扩展;
* 3 有利于程序的维护
*
* 接口编程在设计模式中的体现:开闭原则
* 其遵循的思想是:对扩展开放,对修改关闭。其恰恰就是遵循的是使用接口来实现。在使用面向接口的编程过程
* 中,将具体逻辑与实现分开,减少了各个类之间的相互依赖,当各个类变化时,不需要对已经编写的系统进行
* 改动,添加新的实现类就可以了,不在担心新改动的类对系统的其他模块造成影响。
一,案例需求
在register.jsp上填写用户的信息,点击保存,将用户信息保存到数据库中. 发送激活邮件给注册的用户.
-
修改注册的超链接,跳转到register.jsp
-
在注册页面,修改表单属性 ,提交到UserServlet里面
<form action="/OnlineMall/user">
<input type="hideen" name="method" value="regist"/>
....
</form> -
创建 UserServlet继承BaseServlet,在UserServlet里面创建regist()方法
-
在regist()方法里面
获得请求参数,封装成user对象
调用业务
分发转向
- 用于生成对象的工厂类
package com.factory; import java.io.InputStream; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; /** * 工厂模式:就是传入原材料生产出相应的产品 * * @author LuoJoy * */ public class ContextFactory { /** * 传入一个id返回一个实例 * * @param id * @return * @throws DocumentException * @throws ClassNotFoundException * @throws IllegalAccessException * @throws InstantiationException */ public static Object getInstance(String id) throws DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException { // 1.解析xml,获取class属性值 // 使用Dom4j XPATH工具类读取到配置文件,获取配置信息 // 创建SaxReader对象 SAXReader reader = new SAXReader(); // 将配置文件转换成流 // 使用类加载器将资源文件转换成流 InputStream stream = ContextFactory.class.getClassLoader().getResourceAsStream("context.xml"); Document document = reader.read(stream); // 获取instance id Element element = (Element) document.selectSingleNode("/contexts/instance[@id='" + id + "']"); // 获取instance 上的class Attribute attribute = element.attribute("class"); // 使用属性对象获取属性值 String className = attribute.getValue(); // 使用反射技术通过全类名创建对象 Class<?> clazz = Class.forName(className); Object object = clazz.newInstance(); return object; } }
工厂类配置文件
-
<?xml version="1.0" encoding="UTF-8"?> <contexts> <instance id="user_service" class="com.service.impl.UserServiceImpl"/> <instance id="user_dao" class="com.dao.impl.UserDaoImpl"/> </contexts>
参考jsp页面(主要目的是让大家知道我的前端参数传递及请求路径是如何处理的,这样能更好的理解服务端的代码)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!doctype html> <html> <head></head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>会员登录</title> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.min.css" type="text/css" /> <script src="${pageContext.request.contextPath}/js/jquery-1.11.3.min.js" type="text/javascript"></script> <script src="${pageContext.request.contextPath}/js/bootstrap.min.js" type="text/javascript"></script> <!-- 引入自定义css文件 style.css --> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/style.css" type="text/css"/> <style> body{ margin-top:20px; margin:0 auto; } .carousel-inner .item img{ width:100%; height:300px; } .container .row div{ /* position:relative; float:left; */ } h3 { color: #3164af; font-weight: normal; padding-left: 70px; } </style> </head> <body> <!-- 时间:2015-12-30 描述:菜单栏 --> <%--静态包含头部 --%> <%@ include file="header.jsp" %> <div class="container" style="width:100%;background:url('${pageContext.request.contextPath}/image/regist_bg.jpg');"> <div class="row"> <div class="col-md-2"></div> <div class="col-md-8" style="background:#fff;padding:40px 80px;margin:30px;border:7px solid #ccc;"> <h3>欢迎加入我们</h3> <form class="form-horizontal" style="margin-top:5px;" method="post" action="${pageContext.request.contextPath }/user"> <input type="hidden" name="method" value="regist"> <div class="form-group"> <label for="username" class="col-sm-2 control-label">用户名</label> <div class="col-sm-6"> <input type="text" class="form-control" id="username" placeholder="请输入用户名" name="username"> </div> </div> <div class="form-group"> <label for="inputPassword3" class="col-sm-2 control-label">密码</label> <div class="col-sm-6"> <input type="password" class="form-control" id="inputPassword3" placeholder="请输入密码" name="password"> </div> </div> <div class="form-group"> <label for="confirmpwd" class="col-sm-2 control-label">确认密码</label> <div class="col-sm-6"> <input type="password" class="form-control" id="confirmpwd" placeholder="请输入确认密码"> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-2 control-label">邮箱</label> <div class="col-sm-6"> <input type="email" class="form-control" id="inputEmail3" placeholder="电子邮箱" name="email"> </div> </div> <div class="form-group"> <label for="inputtelephone" class="col-sm-2 control-label">电话</label> <div class="col-sm-6"> <input type="tel" class="form-control" id="inputtelephone" placeholder="电话" name="telephone"> </div> </div> <div class="form-group"> <label for="usercaption" class="col-sm-2 control-label">姓名</label> <div class="col-sm-6"> <input type="text" class="form-control" id="usercaption" placeholder="请输入姓名" name="name"> </div> </div> <div class="form-group opt"> <label for="inlineRadio1" class="col-sm-2 control-label">性别</label> <div class="col-sm-6"> <label class="radio-inline"> <input type="radio" name="sex" id="inlineRadio1" value="male"> 男 </label> <label class="radio-inline"> <input type="radio" name="sex" id="inlineRadio2" value="female"> 女 </label> </div> </div> <div class="form-group"> <label for="date" class="col-sm-2 control-label">出生日期</label> <div class="col-sm-6"> <input type="date" class="form-control" name="birthday"> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <input type="submit" width="100" value="注册" name="submit" border="0" style="background: url('${pageContext.request.contextPath}/images/register.gif') no-repeat scroll 0 0 rgba(0, 0, 0, 0); height:35px;width:100px;color:white;"> </div> </div> </form> </div> <div class="col-md-2"></div> </div> </div> <div style="margin-top:50px;"> <img src="${pageContext.request.contextPath}/image/footer.jpg" width="100%" height="78" alt="我们的优势" title="我们的优势" /> </div> <div style="text-align: center;margin-top: 5px;"> <ul class="list-inline"> <li><a>关于我们</a></li> <li><a>联系我们</a></li> <li><a>招贤纳士</a></li> <li><a>法律声明</a></li> <li><a>友情链接</a></li> <li><a target="_blank">支付方式</a></li> <li><a target="_blank">配送方式</a></li> <li><a>服务声明</a></li> <li><a>广告声明</a></li> </ul> </div> <div style="text-align: center;margin-top: 5px;margin-bottom:20px;"> Copyright © 2005-2016 古代商城 版权所有 </div> </body></html>
-
* 用于处理用户注册业务的方法 * * @param request * @param response */ public String regist(HttpServletRequest request, HttpServletResponse response) { // 接受请求参数 Map<String, String[]> map = request.getParameterMap(); // 创建user对象 User user = new User(); // 使用BeanUtil工具类把请求参数封装到user对象上 try { BeanUtils.populate(user, map); // 还有,uid,state,code 未封装 user.setUid(UUIDUtils.getId());// 封装uid user.setState(Constants.activation); user.setCode(UUIDUtils.getId());// 封装code } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } Boolean flag = false; // 调用业务层的方法完成用户注册 try { IUserService service = (IUserService) ContextFactory.getInstance("user_service"); flag = service.regist(user); } catch (Exception e) { e.printStackTrace(); } if (flag) { // 注册成功,跳转到登陆页面 request.setAttribute("msg", "恭喜您!注册成功,请前往邮箱激活账户"); } else { // 注册失败 request.setAttribute("msg", "注册失败,请重新注册!"); } return "jsp/msg.jsp"; }
5.1调用dao操作数据库
5.2 发送激活的邮件
public interface IUserService { //用户注册方法 public Boolean regist(User user); //用户激活账户 public Boolean doCode(String code); //用户登录 public User doLogin(String usename, String password); }
实现类
package com.service.impl; import org.dom4j.DocumentException; import com.bean.User; import com.dao.intf.IUserDao; import com.factory.ContextFactory; import com.service.intf.IUserService; import com.utils.MailUtils; import com.utils.TransactionManager; public class UserServiceImpl implements IUserService { @Override public Boolean regist(User user) { Boolean falg = false; try { // 开启事务 TransactionManager.startTransaction(); IUserDao dao = (IUserDao) ContextFactory.getInstance("user_dao"); dao.regist(user); // 向用户发送激活邮件 MailUtils.sendMail(user.getEmail(), "尊敬的:" + user.getName() + "欢迎注册古代商城,请点击下面的链接进行激活<a href='localhost:8080/OnlineMall/user?method=active&code=" + user.getCode() + "'>用户激活</a>", "用户账户激活"); // 提交事务 TransactionManager.commit(); falg = true; } catch (Exception e) { e.printStackTrace(); // 如果出现异常回滚 try { TransactionManager.rollback(); } catch (Exception e1) { e1.printStackTrace(); } } try { TransactionManager.close(); } catch (Exception e) { e.printStackTrace(); } return falg; } }
5.创建UserDao数据库访问层,定义一个方法保存用户
-
package com.dao.intf; import java.sql.SQLException; import com.bean.User; public interface IUserDao { public void regist(User user) throws Exception; public void updateCode(String code) throws SQLException; public User doLogin(String usename, String password) throws SQLException; }
package com.dao.impl; import java.sql.SQLException; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import com.bean.User; import com.constant.Constants; import com.dao.intf.IUserDao; import com.utils.C3P0Util; import com.utils.TransactionManager; public class UserDaoImpl implements IUserDao { /** * 用户注册的方法 */ @Override public void regist(User u) throws Exception { QueryRunner runner = new QueryRunner(); String sql = "insert into user values(?,?,?,?,?,?,?,?,?,?);"; runner.update(TransactionManager.getConnectionFromThreadLocal(), sql, u.getUid(), u.getUsername(), u.getPassword(), u.getName(), u.getEmail(), u.getTelephone(), u.getBirthday(), u.getSex(), u.getState(), u.getCode()); } }