大二小学期————搭建一个网购平台
用IDEA配置web项目坑点
用IDEA配置web项目坑点环境问题Day 2Mybatis框架Java框架基础知识在entity层开发Mybatis框架使用mapper层开发mybatisDay 3使用注解的mybatis实现:web基础知识实现取出数据到页面中Day 4分页查询摇乐购工程创建Day 5摇乐购项目摇乐购项目广告轮播实现摇乐购项目登录功能实现登陆后显示用户名实现WeeK 2Day 1完成用户手机验证注册功能1、导入相应依赖jar包2、补全User类成员3、编写dao层接口4、编写工具类CheckCodeUtil5、编写Service层UserService6、编写control层UserServlet7、修改jsp,以及相应jsBUG纠错:1、将ShangYi.jsp重命名为shoplist.jsp2、声明shoplist类3、dao层实现ShopInfoMapper4、在untils包下实现PageBean类,和之前完全一样5、实现业务层ShopInfoService6、新建ShopListServlet并修改端口名为shoplist7、在Index.jsp中新增超链接8、shoplist.jsp需要修改9、效果:Day 2实现筛选展示1、实现ShopInfoVO类,商品信息视图2、实现dao层接口3、测试4、修改ShopService层5、servlet实现6、web端修改物品详情页1、改名为shopdetail.jsp2、新增shopmingxi类3、shopdetail.jsp4、shopinfo新增成员5、dao层实现shopinfo和shopmingxi的查询6、service层新增通过id查商品信息以及明细7、首先实现shoplist.jsp中点击事件的跳转8、实现ShopDetailServlet9、修改shopdetail.jsp点击颜色按钮图片部分消失问题:添加购物车实现1、实现Shopcart类2、实现dao层3、测试方法Day 3续添加购物车4、dao层补充一条通过用户id以及商品id商品颜色商品尺寸查找是否有该记录5、编写Service层6、ShopDetailServlet7、用户登录问题(非标准答案)本地与web端不同步购物车页面实现验证Day 4订单页1、在utils包中实现生成UUID工具类2、实现如下这些类3、实现OrderInfoService4、ShopcartServlet的补充5、web端实现交易页1、拷入jar包2、安装AlipayKeyTool以及注册支付宝沙箱3、在untils下新建AlipayConfig类4、OrderInfoMapper新增5、OrderInfoService6、新建两个Servlet7、新建两个jsp页面Day 5退出功能验证码功能1、导入servlet2、index.jsp界面3、修改IndexServlet的post方法4、index.jsp界面5、RandomServlet.java
环境问题
Day 2
Mybatis框架
Java框架基础知识
- entity层,实体层,用于存放实体类,与数据库中属性基本保持一致,实现get和set方法
- mapper层,别名dao层,对数据库数据持久化操作,其方法语句直接针对数据库操作,主要实现一些增删改查操作
- service层,业务层,给controller层的类提供接口调用,一般声明自己写的方法,具体实现在servicelmpl中
- control层,别名web层,控制层,负责具体模块的业务流程控制,需要调用service逻辑涉及的接口来控制业务流程。controller层通过接收前端H5或者APP传来的参数进行业务操作,再将处理结果返回到前端。
在entity层开发Mybatis框架
项目结构:

需要将mybatis-3.4.6.jar文件移入./web/WEB-INF/lib下(即导入依赖包)(不是lib目录下,根据之前指定的依赖包路径决定依赖包放置位置)
ShopInfo文件的编写:
1、确定ShopInfo类的成员(即读取的数据条目的表头属性),并且为该类的成员编写get & set方法,自动生成代码的方法:光标放置在某一成员上,右键点击generate,选择getter and sentter。本例子中有三个属性,因此生成三个get,三个set IDEA代码生成Generate_idea generate CSDN博客
最后再生成to string方法,用于将读取的数据以string类型输出,并且实现字符串拼接。
@Override是伪代码,表示重写(当然不写也可以),不过写上有如下好处: 1、可以当注释用,方便阅读; 2、编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错。例如,你如果没写@Override,而你下面的方法名又写错了,这时你的编译器是可以编译通过的,因为编译器以为这个方法是你的子类中自己增加的方法。
最终代码如下
xpackage edu.ustb.entity;
public class ShopInfo { private int shopId; private String shopName; private String color;
public int getShopId() { return shopId; }
public void setShopId(int shopId) { this.shopId = shopId; }
public String getShopName() { return shopName; }
public void setShopName(String shopName) { this.shopName = shopName; }
public String getColor() { return color; }
public void setColor(String color) { this.color = color; }
public String toString() { return "ShopInfo{" + "shopId=" + shopId + ", shopName='" + shopName + '\'' + ", color='" + color + '\'' + '}'; }}
ShopInfoMapper.xml文件的编写:
该文件用于编写封装的session方法中如何调用数据库的接口,即select中间的内容,一对select中是一条语句,可以增加,每对select中定义一条mysql语句,以及其调用id,以及返回值类型,本例中返回类型是ShopInfo代表上文中的ShopInfo类
这里的类型需要增加命名空间来指向本项目下的具体类
xxxxxxxxxx <mapper namespace="edu.ustb.entity.ShopInfoMapper">
<select id="selectById" resultType="edu.ustb.entity.ShopInfo"> select * from shopinfo where shopid= #{id}; </select> <!--此处可以添加数据库命令--></mapper>
mybatis-config.xml文件的编写:
是mybatis的配置文件,用于确定所关联的数据库基本信息,需要修改driver驱动器,url接口,username登录用户名,password密码,来连接对应数据库
如果构建的不是空项目而是web项目,则需要将Mybatis-config.xml文件放置在resource默认源目录下
注意附上的注释
xxxxxxxxxx <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!--此处要修改--> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/yaolegoudb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8"/> <property name="username" value="root"/> <property name="password" value="root"/> <!--此处要修改--> </dataSource> </environment> </environments> <mappers> <mapper resource="edu/ustb/entity/ShopInfoMapper.xml"/> </mappers></configuration>
测试文件MybatisTest的编写:
该文件用于测试mybatis框架是否搭建成功,
SqlSession是MyBatis的关键对象,它是应用程序与持久层之间交互操作的一个单线程对象,类似于JDBC中的Connection。SqlSession对象完全包含以数据库为背景的所有执行SQL操作的方法,它的底层封装了JDBC连接,可以用SqlSession实例来直接执行被映射的SQL语句。
mybatis框架过程
- 定义一个Configuration对象,其中包含数据源、事务、mapper文件资源以及影响数据库行为属性设置settings
- 通过配置对象,则可以创建一个SqlSessionFactoryBuilder对象
- 通过 SqlSessionFactoryBuilder 获得SqlSessionFactory 的实例。
- SqlSessionFactory 的实例可以获得操作数据的SqlSession实例,通过这个实例对数据库进行操作
本例子的SqlSessionFactoryBuilder是通过XML配置文件构建出的,而不是通过Java代码生成的
xxxxxxxxxxpackage edu.ustb.test;
import edu.ustb.entity.ShopInfo;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.Before;import org.junit.Test;
import java.io.IOException;import java.io.InputStream;
public class MybatisTest { public void TestSelect() throws IOException{ InputStream inputStream = Resources.getResourceAsStream("edu/ustb/mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
ShopInfo si = (ShopInfo)session.selectOne("edu.ustb.entity.ShopInfoMapper.selectById",30);
// session.getMapper();
System.out.println(si); }
}
使用mapper层开发mybatis
mapper层(dao层)实现mybatis开发,它可以不用写实现类,它能以代理方式自动生成实现代码。
但是,使用mapper开发,必须遵循以下原则:
- mapper.xml文件里的namespace属性值和接口必须一致
- 接口中的方法名必须和mapper.xml中的id保持一致
- 接口中的方法名必须和mapper.xml配置中的resultType保持一致
- 参数的类型保持一致(在有parameterType参数的情况下)
项目结构,新增dao层文件夹:

针对dao包下的ShopInfoMapper:
定义了两个方法,具体实现再xml中,需要保证定义的方法满足之前的mapper开发准则
这里需要定义的是一个接口interfa,而不是类class需要注意
xxxxxxxxxxpackage edu.ustb.dao;
import edu.ustb.entity.ShopInfo;import java.util.ArrayList;
public interface ShopInfoMapper { public ShopInfo selectById(int id); public ArrayList<ShopInfo> selectAll();}
针对ShopInfoMapper.xml:
类似entity层的开发,mapper层需要遵循的规则体现在接口的实现上
xxxxxxxxxx <mapper namespace="edu.ustb.dao.ShopInfoMapper">
<select id="selectById" resultType="edu.ustb.entity.ShopInfo"> select * from shopinfo where shopid= #{id}; </select> <select id="selectAll" resultType="edu.ustb.entity.ShopInfo"> select * from shopinfo; </select></mapper>
针对mybatis-config.xml的修改:
这里是关于mybatis的配置文件,因此当有新增的mapper实现的时候,需要在这里新增对应的源文件
注意代码中附上的注释
xxxxxxxxxx <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!--此处要修改--> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/yaolegoudb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8"/> <property name="username" value="root"/> <property name="password" value="root"/> <!--此处要修改--> </dataSource> </environment> </environments> <mappers> <mapper resource="edu/ustb/entity/ShopInfoMapper.xml"/> <!--新增的关于dao的Mapper配置文件--> <mapper resource="edu/ustb/dao/ShopInfoMapper.xml"/> </mappers></configuration>
测试文件MybatisTest的修改:
xxxxxxxxxxpackage edu.ustb.test;
import edu.ustb.dao.ShopInfoMapper;import edu.ustb.entity.ShopInfo;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.Test;
import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;
public class MybatisTest { public void TestSelect() throws IOException{ InputStream inputStream = Resources.getResourceAsStream("edu/ustb/mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();//entity层的实现// ShopInfo si = (ShopInfo)session.selectOne("edu.ustb.entity.ShopInfoMapper.selectById",30); ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class);//dao层的实现 ShopInfo si = siMapper.selectById(30); System.out.println(si); }
public void TestSelectAll() throws IOException{ InputStream inputStream = Resources.getResourceAsStream("edu/ustb/mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();//entity层的实现// ShopInfo si = (ShopInfo)session.selectOne("edu.ustb.entity.ShopInfoMapper.selectById",30); ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class);//dao层的实现 ArrayList<ShopInfo> list = siMapper.selectAll(); System.out.println(list); }}比起entity层的调用更方便
Day 3
使用注解的mybatis实现:
mybatis的注解和xml方式不能同时对于同一个方法使用,因此该部分需要删除对应方法的xml文件再编写注释。
ShopInfoMapper的修改:
只需要再注释内新增sql语句
xxxxxxxxxxpackage edu.ustb.dao;import edu.ustb.entity.ShopInfo;import java.util.ArrayList;import org.apache.ibatis.annotations.Select;
public interface ShopInfoMapper {
("select * from shopinfo where shopid= #{id}") public ShopInfo selectById(int id);
("select * from shopinfo") public ArrayList<ShopInfo> selectAll(); }
mybatis-config全局配置文件的修改:
需要新增带有注解方法的路径
xxxxxxxxxx <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!--此处要修改--> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/yaolegoudb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8"/> <property name="username" value="root"/> <property name="password" value="root"/> <!--此处要修改--> </dataSource> </environment> </environments> <mappers><!-- <mapper resource="edu/ustb/entity/ShopInfoMapper.xml"/>--> <!--新增的关于dao的Mapper配置文件--><!-- <mapper resource="edu/ustb/dao/ShopInfoMapper.xml"/>--> <!--新增的带有注释的包存在路径--> <package name="edu/ustb/dao"/> </mappers></configuration>
对于测试文件的便捷实现:
新增before和after方法,在每个方法前自动实现sessionFactory的创建与session的实例化,以及在方法结束后对于session的回收关闭
xxxxxxxxxxpackage edu.ustb.test;
import edu.ustb.dao.ShopInfoMapper;import edu.ustb.entity.ShopInfo;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.After;import org.junit.Before;import org.junit.Test;
import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;
public class MybatisTest { private SqlSession session = null;
public void Before() throws IOException{ InputStream inputStream = Resources.getResourceAsStream("edu/ustb/mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); session = sqlSessionFactory.openSession(); }
public void TestSelect() throws IOException{//entity层的实现// ShopInfo si = (ShopInfo)session.selectOne("edu.ustb.entity.ShopInfoMapper.selectById",30); ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class);//dao层的实现 ShopInfo si = siMapper.selectById(30); System.out.println(si); }
public void TestSelectAll() throws IOException{//entity层的实现// ShopInfo si = (ShopInfo)session.selectOne("edu.ustb.entity.ShopInfoMapper.selectById",30); ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class);//dao层的实现 ArrayList<ShopInfo> list = siMapper.selectAll(); System.out.println(list); }
public void After() throws IOException{ session.close(); }}before&after是java默认方法,自动执行
数据项插入、更新、删除的实现:
1、在ShopInfoMapper中新增对应的注解
xxxxxxxxxx("INSERT INTO `shopinfo` (`ShopName`,`ShopMiaoShu`,`ShopPrice`,`ChiCun`,`Color`,`ZhuRenUser`,`ShopTypeId`,`Image`,`Context`,`XiaoLiangCount`) "+ "VALUES (#{shopName},'',100,'',#{color},'',2,'','',0)") public int insert(ShopInfo shopInfo);
("UPDATE `shopinfo` SET `ShopName` = #{shopName}, `Color` = #{color} WHERE `ShopId` = #{shopId}") public int update(ShopInfo shopInfo);
("delete from shopinfo WHERE `ShopId` = #{id}") public int delete(int id);2、在测试中实现相应测试方法
xxxxxxxxxx public void testInsert() throws IOException { ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class); ShopInfo shopInfo = new ShopInfo(); shopInfo.setShopId(128); shopInfo.setShopName("测试商品"); shopInfo.setColor("pink, purple, blue"); int result = siMapper.insert(shopInfo); if (result > 0) { System.out.println("添加成功! ! ! !"); session.commit(); } else{ System.out.println("失败"); } }
public void testUpdate() throws IOException{ ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class); ShopInfo shopInfo = new ShopInfo(); shopInfo.setShopId(128); shopInfo.setShopName("测试商品111111111111"); shopInfo.setColor("pink,purple,blue,yellow"); int result = siMapper.update(shopInfo); if(result > 0) { System.out.println("修改成功!\n"); session.commit(); } else{ System.out.println("失败\n"); } }
public void testDelete() throws IOException { ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class); int result = siMapper.delete( 128); if(result > 0) { System.out.println("删除成功! ! !!"); session.commit(); } else { System.out.println("失败"); } }
事务需要提交以及回滚,类比github库的推送与回滚,在mybatis中提交
session.commit();
web基础知识
HTTP协议是对请求/响应内容的规范
请求/响应都是静态文本,string类型,响应回的内容只能是HTML,表示静态资源
响应码
- 200:正常
- 404:未找到资源
- 500:服务器内部错误
Servlet: 接受并处理请求request;响应结果,服务端的控制器
JSP: 返回一个网页
Tomcat(容器):一个开源小型好用的web应用服务器(用来运行JSP和Servlet)
创建一个Servlet
1、将tomcat包下servlet依赖导入项目指定lib目录下
右键new还是没有servlet则在File-->project struct中找到Modules栏勾选最下方Source Roots,先点apply应用设置,再点close关闭
2、新建一个servlet项目
xxxxxxxxxxpackage edu.ustb.controller;
import javax.servlet.*;import javax.servlet.http.*;import javax.servlet.annotation.*;import java.io.IOException;import java.io.PrintWriter;
(name = "HelloServlet", value = "/HelloServlet")public class HelloServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.write("myfirst Servlet app!"); out.flush(); out.close(); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}}
response.getWriter()返回的是PrintWriter,这是一个打印输出流
- response.getWriter().writer(),只能打印输出文本格式的(包括html标签),不可以打印对象
- response.getWriter().print(),不仅可以打印输出文本格式的(包括html标签),还可以将一个对象以默认的编码方式转换为二进制字节输出

fush:输出缓冲
- flush是把流里的缓冲数据输出,flush以后还能继续使用这个OutputStream
- close是把这个流关闭了,也就是说以后这个OutputStream就不能用了,不过关闭之前会把缓冲的数据都输出
实现取出数据到页面中
报错:Cannot resolve method 'getResourceAsStream' in 'Resources'导入apach下的包而不是javax
Servlet的访问 eg: http://localhost:9527/ustb01/test.jsp
其根目录是Web目录
1、编写service层的读取数据库数据的类ShopInfoService
xxxxxxxxxxpackage edu.ustb.service;
import edu.ustb.dao.ShopInfoMapper;import edu.ustb.entity.ShopInfo;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;
public class ShopInfoService {
public ArrayList<ShopInfo> getAll() {
ArrayList<ShopInfo> list = null; try { InputStream inputStream = Resources.getResourceAsStream("edu/ustb/mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession();
ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class); list = siMapper.selectAll(); }catch (IOException e){ e.printStackTrace(); }
return list; }
}
2、编写控制端Servlet服务
这里调用Service层的方法读取数据,并将数据放入request域中。request域是在Service层以及web端都可以被访问的域,因此将数据放入该域可以发送request以及response请求到index界面,但request仅在当前请求有效。
这里的Servlet服务的值是/hello,因此在后续查看的时候应该查看hello端口,而不是index初始端口
xxxxxxxxxxpackage edu.ustb.controller;
import edu.ustb.entity.ShopInfo;import edu.ustb.service.ShopInfoService;
import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;import java.util.ArrayList;
(name="HelloServlet",value="/hello")public class HelloServlet extends HttpServlet { ShopInfoService shopInfoService = new ShopInfoService();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ //获取列表数据 ArrayList<ShopInfo> list = shopInfoService.getAll(); //将列表存储到request域中 //一个请求会创建一个reques对象,如果在一个请求中经历了多个Servlet,那么多个Seret可以使用request来共享数据。 request.setAttribute("siList",list); //将请求转发到jsp页面 request.getRequestDispatcher("/index.jsp").forward(request,response); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
}}
3、页面端的接收数据:
xxxxxxxxxx<%@ page contentType="text/html;charset=UTF-8" language="java" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><html><head> <title>$Title$</title> <h1>商品列表</h1> <!-- 添加标题 --> <style> h1 { text-align: center; } </style></head><body><div>
<table> <tr> <th>编号</th> <th>商品名称</th> <th>颜色</th> </tr> <c:forEach items="${siList}" var="si"> <tr> <td>${si.shopId}</td> <td>${si.shopName}</td> <td>${si.color}</td> </tr> </c:forEach> </table></div></body></html>
Day 4
新构建Mybatis工具类,包含Session工厂的建立与session的返回
xxxxxxxxxxpackage edu.ustb.utils;
import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;import java.sql.SQLException;
public class MybatisUtil { private static SqlSessionFactory sqlSessionFactory; static{ try{ InputStream inputStream = Resources.getResourceAsStream("edu/ustb/mybatis-config.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); }catch (Exception e){ e.printStackTrace(); } }
public static SqlSession getSesseion() throws SQLException{ return sqlSessionFactory.openSession(); }}static代码块,在加载类的时候自动初始化(执行该代码块内内容),只能在该类被加载的时候执行一次
Service层的重构,使用Mybatis工具类更简单的调用Mybatis,以及溯源异常并抛出,最后保证session的释放
xxxxxxxxxxpackage edu.ustb.service;
import edu.ustb.dao.ShopInfoMapper;import edu.ustb.entity.ShopInfo;import edu.ustb.utils.MybatisUtil;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;
public class ShopInfoService { /* * 返回所有商品 * @return list * */ public ArrayList<ShopInfo> getAll() { ArrayList<ShopInfo> list = null; SqlSession session = null; try { session = MybatisUtil.getSesseion(); //新构建的Mybatis的工具类完成session工厂的建立与返回session ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class); list = siMapper.selectAll(); }catch (Exception e){ e.printStackTrace(); }finally { //finally字段保证即使出现错误,也将执行完该代码块 if(session!=null){ session.close(); } } return list; }}
分页查询
1、在dao层新增对于数据库的分页查找mysql语句,并利用@param进行参数绑定
xxxxxxxxxx("select * from shopinfo limit #{begin}, #{count}") public ArrayList<ShopInfo> selectByPage(("begin") int begin, ("count") int count); //@Param注解用于标注参数映射到哪个名字2、声明一个pageBean类,用于存储有关于页面信息的数据,例如每页条目数,查询第几页,etc
这里使用了泛式编程,方便之后利用该范式存储不同类型的数据进行分页查询
xxxxxxxxxxpackage edu.ustb.utils;
import java.util.List;
public class PageBean <T>{ //T泛型类似CPP泛式编程 //当前页数 private int pageIndex; //每页记录数 private int pageRecord; //总页数 private int pageCount; //总记录数 private int totalRecord;
private List<T> resultList;
public int getPageIndex() { return pageIndex; }
public void setPageIndex(int pageIndex) { this.pageIndex = pageIndex; }
public int getPageRecord() { return pageRecord; }
public void setPageRecord(int pageRecord) { this.pageRecord = pageRecord; }
public int getPageCount() { return pageCount; }
public void setPageCount(int pageCount) { this.pageCount = pageCount; }
public int getTotalRecord() { return totalRecord; }
public void setTotalRecord(int totalRecord) { this.totalRecord = totalRecord; }
public List<T> getResultList() { return resultList; }
public void setResultList(List<T> resultList) { this.resultList = resultList; }}3、在业务层(service)进行计算,连接控制层以及dao层,从控制层读取需要查询的页面数以及每页条目数,通过计算并调用dao层的查询结果,保存结果在pageBean的resultLIst中
xxxxxxxxxx public PageBean<ShopInfo> getPage(PageBean<ShopInfo> pageBean) { SqlSession session = null; try { session = MybatisUtil.getSesseion(); //新构建的Mybatis的工具类完成session工厂的建立与返回session ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class);
int begin = (pageBean.getPageIndex()-1)*pageBean.getPageRecord();
pageBean.setResultList(siMapper.selectByPage(begin,pageBean.getPageRecord())); }catch (Exception e){ e.printStackTrace(); }finally { //finally字段保证即使出现错误,也将执行完该代码块 if(session!=null){ session.close(); } } return pageBean; }4、控制层,完成从web端接受、解析请求,并执行,最后将结果返回web端的功能。
接收到分页查询需求,并得到参数p的值。调用业务层的分页查询方法,并得到返回的resultList,放入request域中,展示在web端
xxxxxxxxxx(name="HelloServlet",value="/hello")public class HelloServlet extends HttpServlet { ShopInfoService shopInfoService = new ShopInfoService();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ //获取列表数据 //ArrayList<ShopInfo> list = shopInfoService.getAll();
String p = request.getParameter("p"); //读取参数 int page = 1; //默认参数为1 try{ page = Integer.parseInt(p); //检查参数是否是整数 }catch(Exception e){ e.printStackTrace(); }
PageBean<ShopInfo> pageBean = new PageBean<ShopInfo>(); pageBean.setPageIndex(page); pageBean.setPageRecord(20); pageBean = shopInfoService.getPage(pageBean);
//将列表存储到request域中 request.setAttribute("siList",pageBean.getResultList()); //将请求转发到jsp页面 request.getRequestDispatcher("/index.jsp").forward(request,response); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
}}
利用url传参,例如
xxxxxxxxxxhttp://localhost:8080/test_war_exploded/hello?p=2
设计底部页面导航栏
方式一:
手动添加页
仅需要在底部增加跳转超链接即可
xxxxxxxxxx <div><%--这里的hello使用的是相对路径--%> <a href="hello">1</a> <a href="hello?p=2">2</a> <a href="hello?p=3">3</a> <a href="hello?p=4">4</a> </div>
方式二:
自动生成页码,可根据数据条目数变化
1、需要知道一共有多少条数据,相应sql语句如下
xxxxxxxxxxselect count(1) from shopinfo;1的用意是在查询结果每一行后都新增一个1,count只用计数1的个数,猜测这里使用了规约算法快速统计
因此在dao层添加相应的条目数查询语句
xxxxxxxxxx("select count(1) from shopinfo") public int selectCount();需要在MybatisTest中进行测试dao层能否正确的取回条目数
2、业务层需要完善PageBean实例的其余参数设置,通过调用dao层的查询条目数,完善totalCount参数的设置,之后通过必要的计算得到相应的页面数,返回pageBean实例回控制层
xxxxxxxxxxpublic PageBean<ShopInfo> getPage(PageBean<ShopInfo> pageBean) { SqlSession session = null; try { session = MybatisUtil.getSesseion(); //新构建的Mybatis的工具类完成session工厂的建立与返回session ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class); //获取总记录数 pageBean.setTotalRecord(siMapper.selectCount()); //计算总页数 if(pageBean.getTotalRecord() % pageBean.getPageRecord() == 0){ pageBean.setPageCount(pageBean.getTotalRecord() / pageBean.getPageRecord()); } else { pageBean.setPageCount(pageBean.getTotalRecord() / pageBean.getPageRecord() + 1); } //计算表中其实条目 int begin = (pageBean.getPageIndex()-1)*pageBean.getPageRecord();
pageBean.setResultList(siMapper.selectByPage(begin,pageBean.getPageRecord())); }catch (Exception e){ e.printStackTrace(); }finally { //finally字段保证即使出现错误,也将执行完该代码块 if(session!=null){ session.close(); } } return pageBean; }
3、相应的在控制层需要修改,此时传递给web端的不再是resultList了,而是pageBean,包含了所有的page信息

4、web端由于接受到的变成pageBean,所以需要读取的是其中的resultList成员,并且循环产生超链接

底部导航栏代码的变动
xxxxxxxxxx<div><%--这里的hello使用的是相对路径--%><%-- <a href="hello">1</a>--%><%-- <a href="hello?p=2">2</a>--%><%-- <a href="hello?p=3">3</a>--%><%-- <a href="hello?p=4">4</a>--%> <c:forEach begin="1" end="${pageData.pageCount}" var="i"> <a href="hello?p=${i}">${i}</a> </c:forEach> </div>
摇乐购工程创建
1、创建module
File->new->module,设置相应的名字,路径,这里命名为yaolegou,后续操作均在yaolegou模块下进行
2、添加框架
右键yaolegou,Add Framework Support,勾选Web Application和web.xml,并点击OK
3、添加依赖
在web/WEB-INF中创建lib目录(Directory),在File->Project Structure中,侧栏选择Modules,选择yaolegou项目,添加依赖(Dependencies) 选择创建的lib目录路径,依赖类型是Jar Directory。最后将前三天工程lib下的依赖包复制移入该路径下,完成依赖的设置
4、导入页面文件
将yaolegou-页面文件内所有全部复制到web目录下
5、设置Tomcat

左上角加号后选择Tomcat Server里的Local
修改名字以和之前项目的tomcat区分,也可以删除之前项目的tomcat,笔者选择设置名字为tomcat
点击右下角的fix添加artifacts

点击+,artifacts,选择添加本项目的,名字为yaolegou的那一项

同时此时可以修改后续访问的url名,不喜欢_war_exploded后缀可以删除。选择Apply应用,ok确定
6、重定向初始界面
由于Tomcat默认index.jsp为首页,这里我们删除原本的index.jsp,使用名为ShouYe的页面为首页,有多种方法重定向,笔者选择修改WEB-INF下的web.xml文件,添加初始页面
xxxxxxxxxx<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <welcome-file-list> <welcome-file>ShouYe.jsp</welcome-file> </welcome-file-list></web-app>
7、设置一些包
在edu.ustb.manager路径下依次new出controller、dao、entity、service、test、utils

8、设置mybatis-config.xml
在edu.ustb.manager路径下直接new,内容从上一个工程复制,注意修改mapper路径
xxxxxxxxxx <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!--此处要修改--> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/yaolegoudb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8"/> <property name="username" value="root"/> <property name="password" value="root"/> <!--此处要修改--> </dataSource> </environment> </environments> <mappers> <package name="edu/ustb/manager/dao"/> </mappers></configuration>
Mybatis分页插件PageHelper
Day 5
摇乐购项目
摇乐购项目广告轮播实现
1、新建entity下的Banner类
需要和mysql table中的名字一致方便调试
xxxxxxxxxx private int id; private String image; private String bgColor; private String href; private int isTingYong; private String beiZhu; private Date CreateTime;右键生成get set方法,为了方便调试也可以生成toString方法
2、新建dao下BannerMapper接口(Interface)
从之前项目复制即可,注意读取的是banner表而不是shopinfo表
xxxxxxxxxxpublic interface BannerMapper { ("select * from banner") public ArrayList<Banner> selectAll();}3、业务层Service,service下的BannerService类实现业务层的功能
同样从之前项目复制,这里变为Banner类即可
xxxxxxxxxxpublic class BannerService { public ArrayList<Banner> getAll() { ArrayList<Banner> list = null; SqlSession session = null; try { session = MybatisUtil.getSesseion(); //Mybatis的工具类完成session工厂的建立与返回session BannerMapper bannerMapper = session.getMapper(BannerMapper.class); list = bannerMapper.selectAll(); }catch (Exception e){ e.printStackTrace(); }finally { //finally字段保证即使出现错误,也将执行完该代码块 if(session!=null){ session.close(); } } return list; }}这里出现了MybatisUtil,因此我们直接从之前项目复制写好的工具类丢入utils package下
MybatisUtil工具类注意复制时修改resources路径为本项目路径,eg:edu/ustb/manager/mybatis-config.xml
4、实现Servlet,控制层命名为IndexServlet
右键new->servlet,如果右键没有请在project structure中勾选本项目的source root
这里将ShouYe.jsp重命名为Index.jsp相应的Day04中修改的默认主页也要相应改成Index.jsp
根据之前项目仿写
xxxxxxxxxx(name = "IndexServlet", value = "/IndexServlet")public class IndexServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //过滤器,过滤非法字符 //暂未实现 BannerService bannerService = new BannerService(); //获取数据 ArrayList<Banner> list = bannerService.getAll(); //放入request域 request.setAttribute("BannerList", list); //请求转发 request.getRequestDispatcher("/Index.jsp").forward(request,response); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}}需要记住的是这里我们将轮播广告的信息list命名为BannnerList,因此接下来需要查找Index.jsp中的BannerList,而不是list
5、Index.jsp的修改
目前已经实现了将BannerList发送至web端,因此这里需要修改相关信息与list中的成员名一致,即一步骤实现的成员名
ctrl+F查找到轮播广告区块
xxxxxxxxxx<!-- 轮播广告 --> <div id="banner_tabs" class="flexslider"> <ul class="slides"> <c:forEach var="banner" items="${BannerList}"> <c:if test="${banner.isTingYong == 0 }"> <li> <a title="" target="_blank" href="${banner.href}"> <img width="1920" height="339" alt="" style="background: url(${banner.image}) no-repeat center;background-size:1200px"> <div style="background: ${banner.bgColor}" id="color"></div> </a> </li> </c:if> </c:forEach> </ul> <ul class="flex-direction-nav"> <li><a class="flex-prev" href="javascript:;">Previous</a></li> <li><a class="flex-next" href="javascript:;">Next</a></li> </ul> <ol id="bannerCtrl" class="flex-control-nav flex-control-paging"> <c:forEach var="banner" items="${BannerList}"> <c:if test="${banner.isTingYong == 0 }"> <li><a>1</a></li> </c:if> </c:forEach> </ol> </div>
6、纠错
如果网页不能正确显示相应图片,需要进行纠错
在test package下新建MybatisTest类并编写以下程序,前提是在第一步骤中自动生成了toString()方法
xxxxxxxxxxpublic class MybatisTest { private SqlSession session = null;
public void Before() throws IOException { InputStream inputStream = Resources.getResourceAsStream("edu/ustb/manager/mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); session = sqlSessionFactory.openSession(); }
public void TestSelectAll() throws IOException{ BannerMapper bannerMapper = session.getMapper(BannerMapper.class);//dao层的实现 ArrayList<Banner> list = bannerMapper.selectAll(); System.out.println(list.toString()); }
public void After() throws IOException{ session.close(); }}右键TestSelectAll()方法进行测试,如果能正确输出相关信息

那么说明dao层及以前层都正确,问题出在Service层Servlet层或者jsp层
- Service层需要检查MybatisUtil工具类编写的源路径是否正确
- Servlet层检查是否发送到正确的页面,eg /Index.jsp or /index.jsp,检查页面的拼写正确
- jsp层需要检查成员拼写是否与第一步骤中一致,BannerList拼写是否与Servlet层中发送到request域的一致,需要注意三点是可以点开的,可以复制步骤一中拼写直接覆盖。
- 查看结果的时候因为Servlet实现的端口位于/IndexServlet,因此查看的url地址为:localhost:8080/yaolegou/IndexServlet
- 目前应该只能实现两种图片轮播,不过观察到文件中存在Banner3.jpg,因此修改数据库banner中第三行的img路径最后图片名为Banner3.jpg就可以实现三张图片轮播,之后不断增加数据库与文件夹image/index_image/中的图片就可以实现轮播广告的扩增
摇乐购项目登录功能实现
ajax异步请求,完成请求功能,优点略
jquery框架,封装好JS的框架
1、声明user类用于存放用户信息
xxxxxxxxxxprivate int id;private String userName;private String password;private int state;private Date CreateTime;private String userNick;并生成相应的set&get方法以及toString方法用于测试
2、写出对应的dao层
根据用户名查询单条用户信息,这里用了表连接的方法同时查询两张表
xxxxxxxxxxpublic interface UserMapper { ("select u.*, ui.UserNick from user u INNER JOIN userinfo ui on u.Username = ui.UserName where u.username = #{username}") public User selectName(("username") String userName);}
3、在业务层进行判断,并且返回判断信息
这里的返回信息需要和Index.jsp里面的判断条件相一致才能完成跳转以及弹窗
xxxxxxxxxxpublic class UserService { /** * 判断登录信息是否正确,并返回对应的判断结果 * @return String */ public String login(User user) { SqlSession session = null; String result = ""; //进行登录信息校验 try { session = MybatisUtil.getSesseion(); //Mybatis的工具类完成session工厂的建立与返回session UserMapper userMapper = session.getMapper(UserMapper.class); User u = userMapper.selectName(user.getUserName());
if(u == null){ result = "dongjie"; } else if(!user.getPassword().equals(u.getPassword())){ //比较输入密码和数据库密码是否一致,这里是能使用equals方法比较字符串而不能使用== result = "beijing"; //密码错误请重新输入 } else { result = "true"; } }catch (Exception e){ e.printStackTrace(); }finally { //finally字段保证即使出现错误,也将执行完该代码块 if(session!=null){ session.close(); } } return result; }}
4、控制层功能实现
这里为了方便与IndexServlet写在一起,原理:Banner广告展示只用了get方法,而不是用post方法,而登录信息只是用了post方法,这样写只是为了方便,但是实际妨碍后期调试
xxxxxxxxxx protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //处理登录功能 request.setCharacterEncoding("utf-8"); //设置编码 response.setCharacterEncoding("utf-8"); UserService userService = new UserService();
//登录 String name = request.getParameter("UserName"); //从文本框拿到对应数据 String pwd = request.getParameter("PassWord");
User user = new User(); user.setUserName(name); user.setPassword(pwd);
//调用service校验账户信息 String result = userService.login(user);
//将结果写回客户端,即作为回调函数的参数 PrintWriter out = response.getWriter(); out.write(result); out.flush(); out.close(); }
5、web端
这里需要修改请求的端口与实现的一致,具体端口名是实现相应功能Servlet的val值
因此需要修改如下,这里笔者将成功登录后的页面设置为跳转回首页,具体可以根据喜好更改
xxxxxxxxxx<script type="text/javascript"> $(function (){ $("#tijiao").click(function (){ //获取用户名和密码 var UserName = $("[name=UserName]").val(); var PassWord = $("[name=PassWord]").val(); //执行异步请求 $.post("IndexServlet",{"UserName":UserName,"PassWord":PassWord},function (Data){ if(Data == "true"){ //加载页面 window.open("IndexServlet","_self"); //此处的端口是登录成功后的端口 }else if(Data == "dongjie"){ $("#text").html("您的账号已违规法律暂被停用!"); $("#beijing").fadeIn("300"); }else{ $("#beijing").fadeIn("300"); } }) }) //关闭提示背景 $("#beijing").click(function (){ $(this).fadeOut("300"); setTimeout(3,function (){ alert(); $("#beijing").fadeOut("300"); }); }) }) </script>
6、调试
在MybatisTest中同样编写TestUserSelectAll()方法来测试能否通过用户名从数据库提取出相应用户信息
xxxxxxxxxx/*测试用户密码从数据库读取正确性 *@return null **/ public void TestUserSelectAll() throws IOException{ UserMapper userMapper = session.getMapper(UserMapper.class); String userName = "1234567"; User user = userMapper.selectName(userName); System.out.println(user); }如果能正确输出,表示数据库到dao层没有问题。
此时打开网页,按f12打开控制台,查看控制台的输出来确定错误位置
登陆后显示用户名实现
request域仅能在当前请求存在,如果跳转则请求不存在。因此引入 ?会话域? (未引入)
1、在业务层新增返回user类的方法
xxxxxxxxxxpublic User getUserByName(String userName) { SqlSession session = null; User user = null; try { session = MybatisUtil.getSesseion(); //Mybatis的工具类完成session工厂的建立与返回session UserMapper userMapper = session.getMapper(UserMapper.class); user = userMapper.selectName(userName); }catch (Exception e){ e.printStackTrace(); } return user; }
2、Servlet层
新增如果校验结果为true,则加载user信息,并将user类放入request域中命名为user

xxxxxxxxxxif("true".equals(result)) { //这样写不会报空指针错误 //加载user数据 user = userService.getUserByName(user.getUserName()); //登录成功将用户信息放入user request.getSession(true).setAttribute("user",user); }
3、web端
在jsp页面中找到相应位置,修改命名与控制层一致
xxxxxxxxxx<ul class="daohang" style="float:right"> <%-- <c:set var="student" value="1" scope="session"></c:set> --%> <c:if test="${ empty user}"> <li class="login_DengLu" id="denglu">您好,请登录</li> </c:if> <c:if test="${ not empty user}"> <li class="xia">${user.userNick} <div class="div_wzdh" onmouseout="wzfl_lk()"> <a href="LeGou.do?UserName=${user.userName}" target="_black">个人管理</a> <a href="LeGou.do?State=Exit">退出账号</a> </div> </li> </c:if>登录效果:

卷王任务:
1、登录功能基础上列表页,加上分页
2、手机短信校验流程
WeeK 2
Day 1
完成用户手机验证注册功能
1、导入相应依赖jar包
略
2、补全User类成员
User类应该包含两张表的内容
xxxxxxxxxx private int id; private String userName; private String password; private int state; private Date CreateTime; private String userNick; private String phone; private String image;
3、编写dao层接口
复制粘贴之前的实现
xxxxxxxxxx("select u.*, ui.UserNick from user u INNER JOIN userinfo ui on u.Username = ui.UserName where u.username = #{username}") public User selectName(("username") String userName);
("select u.*, ui.UserNick from user u INNER JOIN userinfo ui on u.Username = ui.UserName where ui.phone = #{phone}") public User selectByPhone(("phone") String phone);
("INSERT INTO user (UserName,PassWord,State) " +" VALUES (#{userName},#{password},#{state})") public int insertUser(User user);
("INSERT INTO userinfo (username,usernick,phone,sexid,isdianpu,money,dianpumoney,image)" +" VALUES (#{userName},#{userNick},#{phone},3,0,0,0,#{image})") public int insertUserInfo(User user);
4、编写工具类CheckCodeUtil
用来随机生成验证码的复制工具类位于utils包下
xxxxxxxxxxpublic class CheckCodeUtil { /** * @param len 位数 * @return */
public static String getCode(int len) { StringBuilder sb = new StringBuilder(); for (int i = 0; sb.length() < len; i++) { int num = new Random().nextInt(10); sb.append(num); } return sb.toString(); }}
5、编写Service层UserService
UserService类中需要额外添加如下方法
xxxxxxxxxx/** *用于通过用户名查询用户信息 * @param userName 用户姓名 * @return 用户类 */ public User getUserByName(String userName) { SqlSession session = null; User user = null; try { session = MybatisUtil.getSesseion(); //Mybatis的工具类完成session工厂的建立与返回session UserMapper userMapper = session.getMapper(UserMapper.class); user = userMapper.selectName(userName); }catch (Exception e){ e.printStackTrace(); } return user; }xxxxxxxxxx/** *用于添加用户 * @param user 用户信息 * @return int 是否成功 */ public int userAdd(User user){ SqlSession session = null; int result = 0; try { session = MybatisUtil.getSesseion(); user.setImage("attached/TouXiang/default.gif"); UserMapper userMapper = session.getMapper(UserMapper.class); result = userMapper.insertUser(user); result += userMapper.insertUserInfo(user); session.commit(); }catch (Exception ex){ ex.printStackTrace(); session.rollback(); result = 0; }finally { session.close(); } return result; }xxxxxxxxxx/** *通过手机号查询用户,在注册时验证改用户是否被注册过 * @param phone 用户电话 * @return 用户类 */ public User getUserByPhone(String phone) { SqlSession session = null; User user = null; try { session = MybatisUtil.getSesseion(); //Mybatis的工具类完成session工厂的建立与返回session UserMapper userMapper = session.getMapper(UserMapper.class); user = userMapper.selectByPhone(phone); }catch (Exception e){ e.printStackTrace(); } return user; }下面代码中需要填写自己的KeyID,Key,签名名称,模板CODE,需要在阿里云官网查看,此处不赘述如何查看
xxxxxxxxxx/** * 向目标手机号发送目标验证码 * @param phone 用户手机号 * @param code 生成的验证码 * @return 包含是否成功发送的json */ public String sendSms(String phone, String code) { String result = null; /********************此处需要设置为自己的accessKeyId和secret*********************************/ DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "YOUR ACCESSKYEID", "YOUR SECRET"); IAcsClient client = new DefaultAcsClient(profile); CommonRequest request = new CommonRequest();
request.setMethod(MethodType.POST);//注意这四行,与官网所展示的方法不同 request.setDomain("dysmsapi.aliyuncs.com"); request.setVersion("2017-05-25"); request.setAction("SendSms"); request.putQueryParameter("RegionId", "cn-hangzhou"); request.putQueryParameter("PhoneNumbers", phone); request.putQueryParameter("SignName", "你的签名名称"); request.putQueryParameter("TemplateCode", "你的模板CODE"); request.putQueryParameter("TemplateParam", "{\"code\": "+ code +" }");
try { CommonResponse response = client.getCommonResponse(request); result = response.getData(); } catch (ServerException e) { e.printStackTrace(); } catch (ClientException e) { e.printStackTrace(); } return result; }
6、编写control层UserServlet
这里首先需要修改相应端口为reg,因此后续web端中所有请求应该向reg请求而不是ZhuCe.do
xxxxxxxxxx(name = "UserServlet", value = "/reg")public class UserServlet extends HttpServlet {
UserService userService = new UserService();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /*PrintWriter out = response.getWriter();*/ request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=UTF-8");
String State = request.getParameter("State"); String phone = request.getParameter("phone"); if(State == null){ request.setAttribute("phone", phone); request.getRequestDispatcher("/reg2.jsp").forward(request, response); }else if(State.equals("add")){ //获取手机号和密码 String pwd = request.getParameter("pwd");
//生成八位随机数 Random random = new Random(); int suiji = random.nextInt(99999999); String UserName = suiji+"";
//赋值 User u = new User(); u.setUserName(UserName); u.setPassword(pwd); u.setPhone(phone);
//随机生成网名 String[] name1 = new String[]{"最帅的","好看的","美丽的","会撩妹的","爱玩快手的","可爱的","爱听音乐的","爱斗图的","细心的","爱玩抖音的"}; String[] name2 = new String[]{"小红","小仙女","小清新","郭德纲","小白","翠花","熊大","熊二","光头强","老崔"}; int n1 = random.nextInt(10); int n2 = random.nextInt(10); String UserNick = name1[n1]+name2[n2];
u.setUserNick(UserNick);
// //执行增加用户// boolean is = ud.AddUserNameInfo(u); /*****************************重点区域***************************************/ userService.userAdd(u); //此处的State状态由前端传输得到 response.getWriter().print(UserName); }else if(State.equals("yanzhengs")){ //此处是前端当不聚焦于电话对话框是,就会向后端请求yanzhengs,用于确定电话号是否有效 User user = userService.getUserByPhone(phone); response.getWriter().print(user == null); }else if(State.equals("sendsms")){ //此处是按下发送验证码的按钮时向后端请求,作用是随机生成验证码并且发送验证码短信给目标手机号 String code = CheckCodeUtil.getCode(6); String result = userService.sendSms(phone, code); ObjectMapper objMapper = new ObjectMapper(); Map <String, String> rst = objMapper.readValue(result, Map.class); if("OK".equals(rst.get("Code"))){ //如果成功发送验证短信,此时将生成的验证码存储于request域中,以便检查用户输入是否一致 //if("OK".equals(result)){ request.getSession().setAttribute("smsCode", code); response.getWriter().print("true"); } }else if(State.equals("checksms")){ //当前端点击注册按钮时且验证码blank不为空的时候,将发起该请求,进行验证码输入与生成的对比 String code = request.getParameter("smscode"); boolean data = code.equals(request.getSession().getAttribute("smsCode")); response.getWriter().print(data); /*****************************重点区域***************************************/ } }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}
7、修改jsp,以及相应js
ctrl+f搜索ZhuCe.do全部改为reg,例外关于按钮响应的action请求端口也都要改为reg
ZhuCe.js部分代码
xxxxxxxxxx<form action="reg" method="post">ZhuCe.js部分代码
xxxxxxxxxx $("#zhuce").click(function () { $("#phone").html(''); var reg = /^1[3-9]\d{9}$/; if ($("#text").val() == "") { $("#phone").html("必须输入手机号码"); } else if (!reg.test($("#text").val())) { $("#phone").html("手机号码格式不正确"); }else if($("#yzms").val() == ""){ $("#yzmss").html("请输入验证码"); }else if(document.getElementById("tongyi").checked == false){ $("xianshi").fadeIn(1000); }else{ $.post("reg?State=checksms",{"smscode":$("#yzms").val()},function (data){ if(data == 'true'){ $("xianshi").fadeOut(1000); $("form").submit(); }else{ $("#yzmss").html("验证码错误"); } }); } })
$("#yzm").click(function () { var phone = $("[name=phone]").val(); if(!isNaN(phone) && phone != ""){ $.post("reg?State=yanzhengs",{"phone":phone},function (Data){ if(Data == "true"){ $(this).css("background", "#ccc"); miao = 60; $(this).html("请"+miao+"秒后重试"); dates = setInterval("jian()",1000); suijishu=""; $.post("reg?State=sendsms",{"phone":phone},function (data){ if(data == 'true'){ $("#yzmss").html("验证码发送成功"); }
}, "json"); }else{ alert("手机号已注册!"); } }) }else{ alert("请输入正确的手机号码"); } })})ZhuCe2.js部分代码
xxxxxxxxxx$.post("reg",{"State":"add","pwd":pwd,"phone":phone},function (Data){可能修改地方有所遗漏,理解servlet是什么的情况下多用ctrl+f查找自己就能看懂代码,知道需不需要修改
BUG纠错:
打开页面按f12查看控制台报错
问题1:404 notfound ZhuCe.do但是已经修改了jsp中所有ZhuCe成reg了?
按下f12查看源码,发现网页端的源码并未修改,依旧请求ZhuCe.do
解决方案:
2、如果仍然解决不了,例如笔者,可以考虑将浏览器设置为其他浏览器,eg: chrome浏览器,或者清除浏览器缓存,重启电脑等手段。大概率是在tomcat设置中修改浏览器即可解决,不推荐网站中的方法,容易造成其他问题。
3、删除之前发布的内容,清空缓存,再次发布
问题2:单步调试无法调用阿里云发送短信套件,即使换为官方文档也不可以
解决方案:
将JDK换成1.8,笔者试过20.0,1.7都不可以,1.8版本刚刚好,官方给的实例不可以使用,建议使用第五步代码。
由于之前已经下载过jdk,因此配置环境时,只需要修改JAVAHOME的路径即可,可以在cmd中用
java -version查看是否是1.8版本
之后在project struct中修改project的jdk版本即语言等级如下图

同时修改Modules->yaolegou->Dependencies的SDK为1.8版本
如果没有1.8版本可以restart IDEA或者直接将路径设置为jdk1.8安装路径
问题3:Code -> isv.BUSINESS_LIMIT_CONTROL
发送短信数到达上限,即每分钟最多1条,每日最多10条

解决方案:
等第二天,不推荐修改每日上限(富哥除外),即使修改每日最多40条短信
商品页面分页查询实现
1、将ShangYi.jsp重命名为shoplist.jsp
2、声明shoplist类
这里的大小写需要与shoplist.jsp中一致,需要注意检查,用ctrl f快速查找
xxxxxxxxxxprivate int shopId;private String shopName;private double shopPrice;private String image;private String shopMiaoShu;
3、dao层实现ShopInfoMapper
完全复制之前实现的代码
xxxxxxxxxxpublic interface ShopInfoMapper { ("select * from shopinfo where shopid= #{id}") public ShopInfo selectById(int id);
("select * from shopinfo limit #{begin}, #{count}") public ArrayList<ShopInfo> selectByPage(("begin") int begin, ("count") int count); //@Param注解用于标注参数映射到哪个名字
("select count(1) from shopinfo") public int selectCount();}
4、在untils包下实现PageBean类,和之前完全一样
xxxxxxxxxxpublic class PageBean <T>{ //泛式编程 //当前页数 private int pageIndex; //每页记录数 private int pageRecord; //总页数 private int pageCount; //总记录数 private int totalRecord;
private List<T> resultList;
public int getPageIndex() { return pageIndex; }
public void setPageIndex(int pageIndex) { this.pageIndex = pageIndex; }
public int getPageRecord() { return pageRecord; }
public void setPageRecord(int pageRecord) { this.pageRecord = pageRecord; }
public int getPageCount() { return pageCount; }
public void setPageCount(int pageCount) { this.pageCount = pageCount; }
public int getTotalRecord() { return totalRecord; }
public void setTotalRecord(int totalRecord) { this.totalRecord = totalRecord; }
public List<T> getResultList() { return resultList; }
public void setResultList(List<T> resultList) { this.resultList = resultList; }}
5、实现业务层ShopInfoService
xxxxxxxxxx /** * 获取分页数据 * @param pageBean * @return */ public PageBean<ShopInfo> getPage(PageBean<ShopInfo> pageBean) { SqlSession session = null; try { session = MybatisUtil.getSesseion(); //新构建的Mybatis的工具类完成session工厂的建立与返回session ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class); //获取总记录数 pageBean.setTotalRecord(siMapper.selectCount()); //计算总页数 if(pageBean.getTotalRecord() % pageBean.getPageRecord() == 0){ pageBean.setPageCount(pageBean.getTotalRecord() / pageBean.getPageRecord()); } else { pageBean.setPageCount(pageBean.getTotalRecord() / pageBean.getPageRecord() + 1); } //计算表中起始位置 int begin = (pageBean.getPageIndex()-1)*pageBean.getPageRecord();
pageBean.setResultList(siMapper.selectByPage(begin,pageBean.getPageRecord())); }catch (Exception e){ e.printStackTrace(); }finally { //finally字段保证即使出现错误,也将执行完该代码块 if(session!=null){ session.close(); } } return pageBean; }
6、新建ShopListServlet并修改端口名为shoplist
目前只实现部分功能,不具备点击页面跳转功能,页面只是装饰,看着有就行
xxxxxxxxxx(name = "ShopListServlet", value = "/shoplist")public class ShopListServlet extends HttpServlet {
ShopInfoService shopInfoService = new ShopInfoService();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("test/html;charset=UTF-8");
String State = request.getParameter("State"); if(State == null) { //分页 PageBean<ShopInfo> pb = new PageBean<>(); String page = request.getParameter("page"); if (page != null && !page.equals("")) { pb.setPageIndex(Integer.parseInt(page)); }else{ pb.setPageIndex(1); } pb.setPageRecord(20); //接收性别分类 String SexFenLei = request.getParameter("SexFenLei"); String ma = request.getParameter("ma"); String banxing = request.getParameter("banxing"); String s = request.getParameter("s"); String b = request.getParameter("b"); ShopInfo sis = new ShopInfo();
pb = shopInfoService.getPage(pb); //由于http是无状态协议,因此这里将保存到上次跳转前的状态参数初始化再次回到此界面的状态,依次保证页面记住用户上次选择 request.setAttribute("SexFenLei", SexFenLei); request.setAttribute("ma", ma); request.setAttribute("banxing", banxing); request.setAttribute("s", s); request.setAttribute("b", b); request.setAttribute("si",pb.getResultList()); request.setAttribute("pb", pb); request.getRequestDispatcher("/shoplist.jsp").forward(request, response);
}else if(State.equals("Select")){
} }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}}
7、在Index.jsp中新增超链接
ctrl+f 上衣 修改为如下图

并没有使用请求转发,而是直接访问shoplist端口,请求转发是指访问的端口转向另一个端口。
8、shoplist.jsp需要修改
xxxxxxxxxx<c:forEach var="sp" items="${si}"> <%-- 这里需要修改成员和ShopInfo中的成员名一致 --%> <dl class="nan" onclick="window.open('shoplist?State=Select&ShopId=${sp.shopId}')" title="${sp.shopName }"> <div style="width: 240px;height: 220px;overflow: hidden"> <dt style="margin-bottom: 0px;"><img src="${sp.image }" alt="" width="220px"></dt> </div> <dd>¥<span>${sp.shopPrice}</span><p>收藏</p></dd> <dd style="height: 20px;overflow: hidden;">${sp.shopName }</dd> <dd style="overflow: hidden; height: 20px;">${sp.shopMiaoShu }</dd> </dl> </c:forEach>xxxxxxxxxx <%-- 该部分的pb成员名需要修改的和PageBean类中的实现一致 --%> <li onclick="getInfo();return false;">首页</li> <c:forEach var="i" begin="1" end="${pb.pageCount }"> <c:if test="${pb.pageIndex==i }"> <li style="background: #ff3366;color:#fff;" onclick="getInfo(${i});return false;">${i }</li> </c:if> <c:if test="${pb.pageIndex!=i }"> <li onclick="getInfo(${i});return false;">${i }</li> </c:if> </c:forEach> <li onclick="getInfo(${pb.pageCount});return false;">末尾</li>需要与自己写的shopinfo类以及pagebean类成员名一致,不要直接复制
9、效果:

Day 2
补全翻页功能,由于在jsp界面表单提交到post请求中,因此此处使用请求转发,在doPost中转发到doGet方法,即可实现读取与翻页,代码如下
xxxxxxxxxx protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); }
实现筛选展示
1、实现ShopInfoVO类,商品信息视图
该类中封装了商品的筛选信息
xxxxxxxxxxprivate String sexFenlei;private String sizeFenlei;private String banXing;
2、实现dao层接口
能通过筛选信息查询数据库,这里通过脚本语言判断来添加limit信息,为了分页查询需要实现两个方法:通过筛选信息查询ShopInfo、通过筛选信息查询条目数
xxxxxxxxxx("<script>" + "select count(1) from shopinfo where true" + "<if test='siv.sexFenlei!=null'> and shopname like concat('%',#{siv.sexFenlei},'%')</if>" + "<if test='siv.sizeFenlei!=null'> and shopname like concat('%',#{siv.sizeFenlei},'%')</if>" + "<if test='siv.banXing!=null'> and shopname like concat('%',#{siv.banXing},'%')</if>" + "</script>") public int selectCountByCondition(("siv") ShopInfoVO siv);xxxxxxxxxx("<script>" + "select * from shopinfo where true" + "<if test='siv.sexFenlei!=null'> and shopname like concat('%',#{siv.sexFenlei},'%')</if>" + "<if test='siv.sizeFenlei!=null'> and shopname like concat('%',#{siv.sizeFenlei},'%')</if>" + "<if test='siv.banXing!=null'> and shopname like concat('%',#{siv.banXing},'%')</if>" + " limit #{begin}, #{count}" + "</script>") public ArrayList<ShopInfo> queryPageByCondition( ("begin") int begin, ("count") int count, ("siv") ShopInfoVO siv);
3、测试
在Test中测试上述两个方法,以确定dao层以前是否能达到预期
xxxxxxxxxx public void TestQueryPageByCondition() throws IOException{ ShopInfoMapper shopInfoMapper = session.getMapper(ShopInfoMapper.class); ShopInfoVO siv = new ShopInfoVO(); siv.setSexFenlei(""); siv.setSizeFenlei("男"); siv.setBanXing("标准"); ArrayList<ShopInfo> list = shopInfoMapper.queryPageByCondition(0,20,siv); System.out.println(list.toString()); }xxxxxxxxxx public void TestSelectCountByCondition() throws IOException{ ShopInfoMapper shopInfoMapper = session.getMapper(ShopInfoMapper.class); ShopInfoVO siv = new ShopInfoVO(); siv.setSexFenlei(""); siv.setSizeFenlei("男"); siv.setBanXing("标准"); int Cnt = shopInfoMapper.selectCountByCondition(siv); System.out.println(Cnt); }
4、修改ShopService层
之前实现的是所有信息查询,现在需要添加上带有筛选信息的查询,底层实现已经完成,因此只需要将对应位置修改为底层实现接口即可
xxxxxxxxxx/** * 获取分页数据 * @param pageBean * @return */ public PageBean<ShopInfo> getPage(PageBean<ShopInfo> pageBean, ShopInfoVO siv) { SqlSession session = null; try { session = MybatisUtil.getSesseion(); //新构建的Mybatis的工具类完成session工厂的建立与返回session ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class); //获取总记录数 pageBean.setTotalRecord(siMapper.selectCountByCondition(siv)); //计算总页数 int pageCnt = pageBean.getTotalRecord()/ pageBean.getPageRecord(); if(pageBean.getTotalRecord() % pageBean.getPageRecord()>0){ pageCnt++; } pageBean.setPageCount(pageCnt); //计算表中起始位置 int begin = (pageBean.getPageIndex() - 1) * pageBean.getPageRecord();
pageBean.setResultList(siMapper.queryPageByCondition(begin,pageBean.getPageRecord(),siv)); }catch (Exception e){ e.printStackTrace(); }finally { //finally字段保证即使出现错误,也将执行完该代码块 if(session!=null){ session.close(); } } return pageBean; }
5、servlet实现
需要读取表单信息并放入封装好的ShopInfoVO类中,进行查询.
目前暂未实现按照销量、热度排序
xxxxxxxxxx(name = "ShopListServlet", value = "/shoplist")public class ShopListServlet extends HttpServlet {
ShopInfoService shopInfoService = new ShopInfoService();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("test/html;charset=UTF-8");
String State = request.getParameter("State"); if(State == null) { //分页 PageBean<ShopInfo> pb = new PageBean<>(); String page = request.getParameter("page"); if (page != null && !page.equals("")) { pb.setPageIndex(Integer.parseInt(page)); }else{ pb.setPageIndex(1); } pb.setPageRecord(20); //接收性别分类 String SexFenLei = request.getParameter("SexFenLei"); String ma = request.getParameter("ma"); String banxing = request.getParameter("banxing"); String s = request.getParameter("s"); String b = request.getParameter("b"); ShopInfoVO siv = new ShopInfoVO(); //进行判断 if(SexFenLei != null && !SexFenLei.equals("全")){ siv.setSexFenlei(SexFenLei); } if(ma != null && !ma.equals("部")){ siv.setSizeFenlei(ma); } if(banxing != null && !banxing.equals("全部")){ siv.setBanXing(banxing); } //热度、销量排序 //暂未实现
pb = shopInfoService.getPage(pb, siv); //由于http是无状态协议,因此这里将保存到上次跳转前的状态参数初始化再次回到此界面的状态,依次保证页面记住用户上次选择 request.setAttribute("SexFenLei", SexFenLei); request.setAttribute("ma", ma); request.setAttribute("banxing", banxing); request.setAttribute("s", s); request.setAttribute("b", b); request.setAttribute("si",pb.getResultList()); request.setAttribute("pb", pb); request.getRequestDispatcher("/shoplist.jsp").forward(request, response);
}else if(State.equals("Select")){ //通往商品详情页
} }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); }}
6、web端修改
由于jsp的请求端口在week 2 day 1 已经修改,且ShopInfo的成员命名也已经全部统一,因此已经不需要修改
物品详情页
1、改名为shopdetail.jsp
2、新增shopmingxi类
包含如下成员
xxxxxxxxxxprivate int shopId;private String simg;private String bimg;
3、shopdetail.jsp
新增自动缓存以及缓冲大小100kb
xxxxxxxxxx<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" autoFlush="false" buffer="100kb" %>
4、shopinfo新增成员
xxxxxxxxxxprivate String Context;private int shopId;private String shopName;private double shopPrice;private String image;private String shopMiaoShu;private String color;private String chiCun;
5、dao层实现shopinfo和shopmingxi的查询
xxxxxxxxxx("select * from shopinfo where shopid= #{id}") public ShopInfo selectById(("id") int id);("select * from shopmingxi where shopid = #{id}") public ArrayList<ShopMingxi> selectAllMingxi(int id);
6、service层新增通过id查商品信息以及明细
xxxxxxxxxx/** * 通过id搜索商品信息 * @param id 商品id * @return 商品信息 */ public ShopInfo selectById(int id) { SqlSession session = null; ShopInfo shopInfo = null; try { session = MybatisUtil.getSesseion(); //新构建的Mybatis的工具类完成session工厂的建立与返回session ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class); shopInfo = siMapper.selectById(id); } catch (Exception e) { e.printStackTrace(); } finally { //finally字段保证即使出现错误,也将执行完该代码块 if (session != null) { session.close(); } } return shopInfo; }xxxxxxxxxx /** * 返回商品明细 * @param id 商品id * @return 商品明细 */ public ArrayList<ShopMingxi> selectAllMingxi(int id){ SqlSession session = null; ArrayList<ShopMingxi> list = null; try { session = MybatisUtil.getSesseion(); //新构建的Mybatis的工具类完成session工厂的建立与返回session ShopInfoMapper siMapper = session.getMapper(ShopInfoMapper.class); list = siMapper.selectAllMingxi(id); }catch (Exception e){ e.printStackTrace(); }finally { //finally字段保证即使出现错误,也将执行完该代码块 if(session!=null){ session.close(); } } return list; }
7、首先实现shoplist.jsp中点击事件的跳转
xxxxxxxxxx<c:forEach var="sp" items="${si}"> <%-- 这里需要修改成员和ShopInfo中的成员名一致 --%> <%-- 此处通过点击直接向shopdetail端口发送请求 --%> <dl class="nan" onclick="window.open('ShopDetail?ShopId=${sp.shopId}')" title="${sp.shopName }"> <div style="width: 240px;height: 220px;overflow: hidden"> <dt style="margin-bottom: 0px;"><img src="${sp.image }" alt="" width="220px"></dt> </div> <dd>¥<span>${sp.shopPrice}</span><p>收藏</p></dd> <dd style="height: 20px;overflow: hidden;">${sp.shopName }</dd> <dd style="overflow: hidden; height: 20px;">${sp.shopMiaoShu }</dd> </dl> </c:forEach>
8、实现ShopDetailServlet
控制层通过接收由shoplist点击事件传来的shopid,再调用服务层的查询方法,最后放置对应的信息到request域中
xxxxxxxxxx(name = "ShopDetailServlet", value = "/ShopDetail")public class ShopDetailServlet extends HttpServlet {
ShopInfoService shopInfoService = new ShopInfoService();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("test/html;charset=UTF-8");
String State = request.getParameter("State"); if(State == null){ String ShopId = request.getParameter("ShopId"); ShopInfo si = shopInfoService.selectById(Integer.parseInt(ShopId)); String color = si.getColor(); String[] Color = color.split(","); String chicun = si.getChiCun(); String[] ChiCun = chicun.split(",");
List<ShopMingxi> ShopMingXiList = shopInfoService.selectAllMingxi(Integer.parseInt(ShopId));
request.setAttribute("ChiCun",ChiCun); request.setAttribute("Color",Color); request.setAttribute("ShopMingXiList",ShopMingXiList); request.setAttribute("si",si); request.getRequestDispatcher("/shopdetail.jsp").forward(request,response); }else if(State.equals("Color")){
} }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); }}
9、修改shopdetail.jsp
通过ctrl+f搜索si,将所有si.xxx格式的xxx修改的和ShopInfo类中成员名一致,以及请求端口修改的和ShopDetailServlet的val参数一致
如果出现了找不到context成员的问题,且换浏览器,重启,删除再发布包都无法解决,可以用该命令调用成员方法,避开直接调用
xxxxxxxxxx<div id="img"><!-- 内容简介 -->${si.getContext()}</div>
点击颜色按钮图片部分消失问题:
没听,不点击颜色按钮即可解决
添加购物车实现
1、实现Shopcart类
xxxxxxxxxx private int id; private String userName; private String shopName; private String chiCun; private String color; private int count; private double price; private String image; private int shopId;
2、实现dao层
ShopcartMapper
xxxxxxxxxx//根据userName获取购物车数据("select * from gouwuche where UserName= #{username}") public ArrayList<Shopcart> selectByUserName(("username") String username);
//插入购物车("INSERT INTO `gouwuche` (`UserName`,`ShopName`,`ChiCun`,`Color`,`Count`,`Price`,`Image`,`ShopId`) " +" VALUES (#{userName},#{shopName},#{chiCun},#{color},#{count},#{price},#{image},#{shopId})") public int insert(Shopcart shopcart);
//update购物车数量("update gouwuche set Count=#{shopcart.count} where Id=#{shopcart.id}") public int updateCnt(("shopcart") Shopcart shopcart);
//delete by id("delete from gouwuche where id=#{id}") public int delete(int id);
3、测试方法
插入测试
xxxxxxxxxx public void TestShopcartInsert() throws IOException{ ShopcartMapper shopcartMapper = session.getMapper(ShopcartMapper.class); Shopcart shopcart = new Shopcart(); shopcart.setUserName("123456"); shopcart.setShopName("YiFu"); shopcart.setChiCun("中"); shopcart.setColor("浅灰色"); shopcart.setCount(1); shopcart.setImage("attached/image/1.jpg"); shopcart.setPrice(20); shopcartMapper.insert(shopcart); session.commit(); }去数据库gouwuche表单下刷新查看
搜索测试
xxxxxxxxxx public void TestShopcartSelect() throws IOException{ ShopcartMapper shopcartMapper = session.getMapper(ShopcartMapper.class); Shopcart shopcart = new Shopcart(); shopcart.setId(38); shopcart.setCount(3); shopcartMapper.updateCnt(shopcart); session.commit(); }删除测试
xxxxxxxxxx public void TestShopcartDelete() throws IOException{ ShopcartMapper shopcartMapper = session.getMapper(ShopcartMapper.class); shopcartMapper.delete(38); session.commit(); //System.out.println(list.toString()); }根据用户名测试的代码不小心覆盖了,和根据id搜索极为类似,可以自行尝试实现
Day 3
续添加购物车
4、dao层补充一条通过用户id以及商品id商品颜色商品尺寸查找是否有该记录
xxxxxxxxxx("select * from gouwuche where UserName= #{sc.userName} and ShopId = #{sc.shopId} and ChiCun = #{sc.chiCun} and Color = #{sc.color}") public Shopcart selectByUserNameAndShopId(("sc") Shopcart shopcart);
5、编写Service层
用于逻辑判断,首先查询之前是否添加过该记录到购物车中,添加过则只修改数量,没有添加过则调用additem方法添加
xxxxxxxxxxpublic class ShopcartService { public int shopcartItemAdd(Shopcart sc) { SqlSession session = null; int result = 0; try{ session = MybatisUtil.getSesseion(); ShopcartMapper scMapper = session.getMapper(ShopcartMapper.class); Shopcart shopcart = scMapper.selectByUserNameAndShopId(sc); if(shopcart == null) { //判断购物车里面没有该商品 则会增加一条购物车记录 result = scMapper.insert(sc); }else{ shopcart.setCount(shopcart.getCount()+sc.getCount()); result = scMapper.updateCnt(shopcart); } session.commit(); }catch (Exception e){ e.printStackTrace(); session.rollback(); }finally { session.close(); } return result; }}
6、ShopDetailServlet
在原有的基础上新增State=add状态
从前端读取商品信息,并封装在shopcart类中,之后调用业务层添加到购物车(购物车中是否存在该商品的逻辑判断在业务层已经实现)
xxxxxxxxxxelse if(State.equals("add")){ String img = request.getParameter("img"); String shopid = request.getParameter("id"); String shopname = request.getParameter("shopname"); String yanse = request.getParameter("yanse"); String chicun = request.getParameter("chicun"); String jiage = request.getParameter("jiage"); String count = request.getParameter("count"); String userName = request.getParameter("UserName"); Shopcart sc = new Shopcart(); sc.setShopName(shopname); sc.setImage(img); sc.setUserName(userName); sc.setPrice(Double.parseDouble(jiage)); sc.setShopId(Integer.parseInt(shopid)); sc.setCount(Integer.parseInt(count)); sc.setColor(yanse); sc.setChiCun(chicun);
ShopcartService scService = new ShopcartService(); int result = scService.shopcartItemAdd(sc); response.getWriter().print(result>0); }
7、用户登录问题(非标准答案)
这里由于已经在跳转的同时保存了request域进行转发,因此只需要修改各jsp页面能正确读取到用户信息即可
shoplist.jsp需要修改
搜索user将所有user.xxx后面的xxx修改的名字与User类中成员一致
shopdetail.jsp需要修改
ctrl+f搜索ui将所有ui.xxx后的xxx修改的名字域User类中成员一致
即可保证在首页登陆后,每个页面都可以读取到用户信息,并且依次传递给下一个页面
本地与web端不同步
Edit configurations->deployment清除
右键清除

购物车页面实现
没有听课笔者自己的实现方法,并不标准,但是至少能跑
1、考虑到页面中存在zhuRenUser,因此扩充Shopcart类添加zhuRenUser成员
xxxxxxxxxx private int id; private String userName; private String shopName; private String chiCun; private String color; private int count; private double price; private String image; private int shopId; private String zhuRenUser;
2、dao层实现
由于涉及到数据库的查询,考虑到购物车是按照用户视图来查看的,每个人只能看到自己的购物车,且只能增删改查自己的购物车,而新增商品在商品详情页已经实现,这里只需要实现修改商品个数、查询自己购物车数据以及删除该条目商品
其中查询购物车数据又分为,通过购物车id来查询单挑数据,以及通过用户名查看该用户名下所有商品,因此有两条关于查询的实现
不过由于zhuRenUser在另一个表,因此我们查询时需要用到多表连接查询
查询
xxxxxxxxxx//select by id ("select * from gouwuche where Id = #{id}") public Shopcart selectById(int id);
//select by userName("select gwc.*,si.ZhuRenUser from gouwuche gwc INNER JOIN shopinfo si on gwc.ShopId=si.ShopId where gwc.UserName= #{username}") public ArrayList<Shopcart> selectByUserName(("username") String username);修改数量
xxxxxxxxxx//update购物车数量 ("update gouwuche set Count=#{Shopcart.count} where Id=#{Shopcart.id}") public int updateCnt(("Shopcart") Shopcart shopcart);删除
xxxxxxxxxx//delete by id ("delete from gouwuche where Id=#{id}") public int delete(int id);
3、业务层实现 这里在ShopcartService的基础上封装了在dao层新实现的数据库交互逻辑
xxxxxxxxxx/** * 根据用户名获取用户购物车信息 * @param userName * @return */ public ArrayList<Shopcart> shopcartSelectItem(String userName) { SqlSession session = null; ArrayList<Shopcart> list =null; try{ session = MybatisUtil.getSesseion(); ShopcartMapper scMapper = session.getMapper(ShopcartMapper.class); list = scMapper.selectByUserName(userName); }catch (Exception e){ e.printStackTrace(); session.rollback(); }finally { session.close(); } return list; }
/** * 更新数据库 * @param id * @param cnt * @return */ public int shopcartUpdateItem(int id, int cnt) { SqlSession session = null; int result = 0; try{ session = MybatisUtil.getSesseion(); ShopcartMapper scMapper = session.getMapper(ShopcartMapper.class); Shopcart shopcart = new Shopcart(); shopcart.setId(id); shopcart.setCount(cnt); result = scMapper.updateCnt(shopcart); session.commit(); }catch (Exception e){ e.printStackTrace(); session.rollback(); }finally { session.close(); } return result; }
/** * 根据id查询shopcart * @param id * @return */ public Shopcart shopcartSelectByIdItem(int id) { SqlSession session = null; Shopcart shopcart = null; try{ session = MybatisUtil.getSesseion(); ShopcartMapper scMapper = session.getMapper(ShopcartMapper.class); shopcart = scMapper.selectById(id); }catch (Exception e){ e.printStackTrace(); session.rollback(); }finally { session.close(); } return shopcart; }
/** * 根据id删除购物车中对应商品 * @param id * @return */ public int shopcartDeleteById(int id) { SqlSession session = null; int result = 0; try{ session = MybatisUtil.getSesseion(); ShopcartMapper scMapper = session.getMapper(ShopcartMapper.class); result = scMapper.delete(id); session.commit(); }catch (Exception e){ e.printStackTrace(); session.rollback(); }finally { session.close(); } return result; }!!涉及到数据库数据修改的操作一定要加commit提交!!
4、Servlet层实现
为了区分开,这里新构建一个Servlet命名为ShopcartServlet,并将端口值命名为Shopcart
该控制层主要针对购物车页面。
- 在其余页面的顶部可以通过跳转来到购物车界面,此时State状态为null。通过查看GouWuChe.jsp我们发现前端会传递用户相关信息,因此可以利用用户的信息进行查询相关数据调用在业务层实现的通过用户名查询购物车数据即可。
- 在GoWuChe的加减物品数量的时候会访问该端口,并且State状态为"AddCount"||"JianCount",需要进行Update操作,加减通过状态参数判断,之后将修改后结果传递给业务层即可。
- GoWuChe界面进行商品条目删除也会访问该端口,此时只用直接调用业务层的delete方法即可
xxxxxxxxxx(name = "ShopcartServlet", value = "/Shopcart")public class ShopcartServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("test/html;charset=UTF-8");
String State = request.getParameter("State"); if(State==null) { //没有状态,代表可能从任何地方跳转到购物车界面,此时读取用户名,展示该用户的所有商品 String UserName = request.getParameter("UserName"); UserService userService = new UserService(); User user = userService.getUserByName(UserName); ShopcartService shopcartService = new ShopcartService(); ArrayList<Shopcart> list = shopcartService.shopcartSelectItem(user.getUserName());
request.setAttribute("GouWuChelist", list); request.setAttribute("user", user); request.getRequestDispatcher("GouWuChe.jsp").forward(request, response); }else if(State.equals("AddCount")||State.equals("JianCount")){ //购物车中商品数量的变化 String id = request.getParameter("id"); ShopcartService shopcartService = new ShopcartService(); Shopcart shopcart = shopcartService.shopcartSelectByIdItem(Integer.parseInt(id)); if(State.equals("AddCount")){ shopcart.setCount(shopcart.getCount()+1); } if(State.equals("JianCount")&&shopcart.getCount()>1) { shopcart.setCount(shopcart.getCount()-1); }
int result = shopcartService.shopcartUpdateItem(shopcart.getId(),shopcart.getCount()); response.getWriter().print(result); }else if(State.equals("del")){ //根据id删除商品,并写回是否成功删除 String id = request.getParameter("id"); ShopcartService shopcartService = new ShopcartService(); int result = shopcartService.shopcartDeleteById(Integer.parseInt(id)); response.getWriter().print(result>0); } }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); }}
5、web端
为了方便调试,在index.jsp中添加购物车的超链接,并且传递用户信息
xxxxxxxxxx<li onclick="window.open('Shopcart?UserName=${user.userName}')"><img src="Image/Index_Image/xiaogouwuche.png" alt=""> 购物车</li>
给的GouWuChe.js存在问题需要修改两个地方
不修改会造成更新个数与删除不成功的问题
1)222~224行交换shopid和id后面eq()括号中的参数,交换后如下
xxxxxxxxxxvar shopid = $(zhe).parent().parent().parent().children().eq(2).val(); var username = $(zhe).parent().parent().parent().children().eq(1).val(); var id = $(zhe).parent().parent().parent().children().eq(0).val();
2)190~192行同样是shopid和id后eq()后两个参数,交换后如下
xxxxxxxxxxvar shopid = $(zhe).parent().parent().parent().children().eq(2).val(); var username = $(zhe).parent().parent().parent().children().eq(1).val(); var id = $(zhe).parent().parent().parent().children().eq(0).val();
为了方便知道是否成功修改数据库,加上一个弹窗告知是否修改成功
194行附近
xxxxxxxxxx $.post("Shopcart?State=AddCount",{"id":id,"username":username,"shopid":shopid,"count":1},function (result){ if(result>0) alert("更新成功"); else alert("更新失败");226行附近
xxxxxxxxxx$.post("Shopcart?State=JianCount",{"id":id,"username":username,"shopid":shopid,"count":1},function (result){ if(result>0) alert("更新成功"); else alert("更新失败"); })276行附近
xxxxxxxxxx $("#jg2").html("¥"+sums+".0"); alert("删除成功"); }else{ alert("删除失败"); }
在GoWuChe.jsp页面中需要修改所有的user.xxx后的xxx需要和User中一致
如果碰到user.userinfo.xxx的情况我们并没有在user中嵌套类,因此直接删除userinfo,改成user.xxx且xxx名字和user中一致
所有可能请求Shopcart端口的地方经过排查都在GouWuChe.js中,
只需将GouWuChe.js中的所有端口改成Shopcart
由于修改名字地方大小写地方过多,不在此罗列,可以直接运行页面,如果报错404not found的时候会报出没有找到的行数,附近代码,可以快速定位没有修改的地方。
验证
注意gouwuche数据库可能是空的,需要先添加物品在购物车中,可以在数据库中手动添加,也可以在页面中点击添加到购物车的按钮添加。
在GouWuChe页面按加减号修改数量后在数据库中验证数量是否同步修改,如果没有同步修改,可以在mybatistest中测试验证正确性,排查错误地点。
Day 4
订单页
1、在utils包中实现生成UUID工具类
xxxxxxxxxxpublic class UUIDUtil { public static String getUUID(){ UUID uuid = UUID.randomUUID(); return uuid.toString().replace("-",""); }}UUID相应jar包如下
2、实现如下这些类

- City.java
xxxxxxxxxx private int id; private String cityName; private int shengId;- Distric.java
xxxxxxxxxx private int quid; private String quName; private int cityId;- OrderInfo.java
xxxxxxxxxx private int id; private String dingdanNumber; private String zhuRenUser; private double price; private int stateId; private String createTime; private String userName; private int zhifuId; private int addressId;
private OrderState orderState; private PayType payType; private Province shAddress; private List<OrderItem> itemlist; private ShopInfo si; private User user;- OrderItem.java
xxxxxxxxxx private int id; private String dingdanNumber; private int shopId; private String chiCun; private String color; private int count; private String userName; private ShopInfo si; private User user; private String myUser; private String createTime; private String state; private OrderState orderState; private int stateId;- OrderState.java
xxxxxxxxxx private int stateId; public String stateName;- PayType.java
xxxxxxxxxx private int stateId; public String stateName;- Province.java
xxxxxxxxxx private int shengId; public String shengName;- SHAddress.java
xxxxxxxxxx private int id; private String userName; private String name; private String phone; private String byPhone; private String city; private String address; private String label; private int defaults;
3、实现OrderInfoService
xxxxxxxxxx/** * 新增订单到数据库中 * @param orderInfo * @return */ public int orderAdd(OrderInfo orderInfo) { SqlSession session = null; int result = 0; try { session = MybatisUtil.getSesseion(); OrderInfoMapper orderInfoMapper = session.getMapper(OrderInfoMapper.class); result = orderInfoMapper.insertOrderInfo(orderInfo); if(result>0){ for(OrderItem item : orderInfo.getItemlist()){ result = orderInfoMapper.insertOrderItem(item); } } session.commit(); }catch (Exception e){ e.printStackTrace(); session.rollback(); }finally { session.close(); } return result; }
/** * 通过用户名查询所有收货地址 * @param userName * @return */ public List<SHAddress> queryAddrByUsername(String userName){ List<SHAddress> list = null; SqlSession session = null; try { session = MybatisUtil.getSesseion(); //Mybatis的工具类完成session工厂的建立与返回session OrderInfoMapper orderInfoMapper = session.getMapper(OrderInfoMapper.class); list = orderInfoMapper.queryShAddrByUserName(userName); }catch (Exception e){ e.printStackTrace(); }finally { //finally字段保证即使出现错误,也将执行完该代码块 if(session!=null){ session.close(); } } return list; }
/** * 查询所有省份 * @return */ public List<Province> queryAllProvince(){ SqlSession session = null; List<Province> list = null; try{ session = MybatisUtil.getSesseion(); //Mybatis的工具类完成session工厂的建立与返回session OrderInfoMapper orderInfoMapper = session.getMapper(OrderInfoMapper.class); list = orderInfoMapper.queryAllProvince(); }catch (Exception e){ e.printStackTrace(); }finally { //finally字段保证即使出现错误,也将执行完该代码块 if(session!=null){ session.close(); } } return list; }
/** * 查询所有支付方式 * @return */ public List<PayType> queryAllPayType(){ SqlSession session = null; List<PayType> list = null; try{ session = MybatisUtil.getSesseion(); //Mybatis的工具类完成session工厂的建立与返回session OrderInfoMapper orderInfoMapper = session.getMapper(OrderInfoMapper.class); list = orderInfoMapper.queryAllPayType(); }catch (Exception e){ e.printStackTrace(); }finally { //finally字段保证即使出现错误,也将执行完该代码块 if(session!=null){ session.close(); } } return list; }
4、ShopcartServlet的补充
Why:为什么修改补充在ShopcartServlet?
原理:清空购物车的时候,点击提交按钮就会自动产生商品信息,可以查看GouWuChe页面的提交按钮触发点击事件的时候,会访问Shopcart端口,并且参数State设置为submit。
Why:Shopcart端口又如何跳转到交易页面?
原理:通过请求转发,当携带submit访问Shopcart端口的时候,该端口进行逻辑处理,并封装好信息到request域中,之后通过如下命令,将请求转发到order.jsp,如此便实现了页面跳转的同时并且在后端实现了信息处理,并且是隐式传参,安全性较高。
xxxxxxxxxxrequest.getRequestDispatcher("/order.jsp").forward(request,response);
以下只展示State==submit的代码,其余部分之前已经实现
xxxxxxxxxxelse if(State.equals("submit")){ /** * 前往订单页面 */ OrderInfoService orderInfoService = new OrderInfoService(); ShopInfoService shopInfoService = new ShopInfoService(); String UserName = request.getParameter("UserName"); List<SHAddress> shAddressList = orderInfoService.queryAddrByUsername(UserName); //创建一个订单 OrderInfo orderInfo = new OrderInfo(); //给订单生成订单编号(UUDID) UUIDUtil uuidUtil = new UUIDUtil(); String uuid = uuidUtil.getUUID(); orderInfo.setDingdanNumber(uuid); orderInfo.setUserName(UserName); orderInfo.setZhuRenUser(UserName);
//处理订单,得到订单相关信息 String[] id = request.getParameterValues("ids"); String[] shopid = request.getParameterValues("shopid"); String[] shangpincount = request.getParameterValues("shangpincount"); String[] shangpincolor = request.getParameterValues("shangpincolor"); String[] shangpinchicun = request.getParameterValues("shangpinchicun"); String[] username = request.getParameterValues("usernames");
//王订单详情商品列表插入数据 OrderItem orderItem; orderInfo.setItemlist(new ArrayList<OrderItem>()); int totalCnt = 0; double totalPrice = 0; for(int i=0;i<shangpinchicun.length;++i){ if(!shangpinchicun[i].equals("")){ orderItem = new OrderItem(); orderItem.setChiCun(shangpinchicun[i]); orderItem.setColor(shangpincolor[i]); int count = Integer.parseInt(shangpincount[i]); orderItem.setCount(count); orderItem.setDingdanNumber(uuid); orderItem.setShopId(Integer.parseInt(shopid[i])); orderItem.setUserName(username[i]); orderItem.setMyUser(UserName); orderItem.setSi(shopInfoService.selectById(orderItem.getShopId())); orderInfo.getItemlist().add(orderItem); totalCnt+=count; totalPrice+=orderItem.getSi().getShopPrice()*count; } } orderInfo.setPrice(totalPrice); //订单数据添加 orderInfoService.orderAdd(orderInfo);
List<Province> proList = orderInfoService.queryAllProvince(); List<PayType> ptList = orderInfoService.queryAllPayType();
//订单详情表里面的信息 request.setAttribute("list",orderInfo.getItemlist()); request.setAttribute("ZhiFuTypeList",ptList); request.setAttribute("ShengList",proList); request.setAttribute("ShouHuolist",shAddressList); request.setAttribute("UserName",UserName); request.setAttribute("totalCnt",totalCnt); request.setAttribute("orderInfo",orderInfo); request.getRequestDispatcher("/order.jsp").forward(request,response);
}
5、web端实现
在钉钉下载order.jsp替换原本的order.jsp
修改GouWuChe.jsp第122行请求地址
xxxxxxxxxx<form action="Shopcart?State=submit&UserName=${user.userName }&DingDanNumber=<%=DingDanNumber %>" method="post" id="form">
在order.jsp中确保所有yyy.xxx的成员与实现的yyy类中成员命名一致,yyy可能与类名不一致此时可以通过查看其yyy的items值并且在ShopcartServlet中找到items对应的真实类名对应

找不全也可以通过直接运行程序,通过报错快速定位not found的行数,再进行修改
交易页
1、拷入jar包
alipay-sdk-java-4.34.86.ALL.jar
commons-logging-1.2.jar
2、安装AlipayKeyTool以及注册支付宝沙箱
下载AlipayKeyTool-2.0.2.exe到默认C盘地址(之后称之为软件端)
支付宝沙箱模式官网(之后称之为网页端):https://open.alipay.com/platform/appDaily.htm?tab=info
网站支付官方文档(遇到问题再看):电脑网站支付快速接入 - 支付宝文档中心 (alipay.com)
3、在untils下新建AlipayConfig类
直接拷贝钉钉群中AlipayConfig.java代码,删除app_id、merchant_private_key、alipay_public_key的参数后续需要填写自己的参数
在软件端中生成公钥和私钥

私钥设置为AlipayConfig.java中merchant_private_key
将公钥复制输入到沙箱支付网页端,在加签内容配置粘贴公钥,点击生成,得到支付宝公钥,复制到AlipayConfig.java中alipay_public_key处

在网页端的沙箱工具处扫码下载沙箱支付宝APP,在网页端的沙箱账号处得到买家的账号和登录密码,在沙箱支付宝APP中可以登录买家账号,账户余额可以自己充值然后发个pyq
在下载的支付宝沙盒版,登录虚拟的买家账号,不是真实的账号

4、OrderInfoMapper新增
xxxxxxxxxx//更新支付状态 ("update dingdanbiao set StateId=#{stateId} where DingDanNumber=#{dingdanNumber}") public int updateState(("dingdanNumber") String dingdanNumber, ("stateId") int stateId);
5、OrderInfoService
新增一个方法
xxxxxxxxxx/** * 更新支付状态 * @param dingdanNumber * @param stateId * @return */ public int updateState(String dingdanNumber, int stateId) { SqlSession session = null; int result = 0; try { session = MybatisUtil.getSesseion(); OrderInfoMapper oiMapper = session.getMapper(OrderInfoMapper.class); result = oiMapper.updateState(dingdanNumber, stateId); session.commit(); }catch (Exception e){ e.printStackTrace(); session.rollback(); }finally { session.close(); } return result; }
6、新建两个Servlet
OrderPayServlet
xxxxxxxxxx(name = "OrderPayServlet", value = "/order/pay")public class OrderPayServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String orderNumber = request.getParameter("dingdannumber"); String orderPrice = request.getParameter("dingdanjine"); String orderName = request.getParameter("UserName"); String orderAddr = request.getParameter("address");
// 获得初始化的AlipayClient AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type); // 设置请求参数 AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); alipayRequest.setReturnUrl(AlipayConfig.return_url); alipayRequest.setNotifyUrl(AlipayConfig.notify_url); try { alipayRequest.setBizContent("{\"out_trade_no\":\"" + orderNumber + "\"," + "\"total_amount\":\"" + orderPrice + "\"," + "\"subject\":\"" + orderName + "\"," + "\"body\":\"" + orderAddr + "\"," + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}"); // 请求 String result = alipayClient.pageExecute(alipayRequest).getBody(); // 输出 pay页面取出// model.addAttribute("result", result); request.setAttribute("result", result); } catch (Exception e) { e.printStackTrace(); } // 这个是渲染到视图中,在pay视图中使用el方式将 result对象数据展示,由result对象进行向阿里支付系统发送构建的请求// return "order/alipay";
request.getRequestDispatcher("/order/alipay.jsp").forward(request, response); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); }}
PayResultServlet
xxxxxxxxxx(name = "PayResultServlet", value = "/order/payresult")public class PayResultServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { /* * * 功能:支付宝服务器同步通知页面 日期:2017-03-30 说明: * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。 页面功能说明************************* * 该页面仅做页面展示,业务逻辑处理请勿在该页面执行 */ // 获取支付宝GET过来反馈信息 Map<String, String> params = new HashMap<String, String>(); Map<String, String[]> requestParams = request.getParameterMap(); for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) { String name = (String) iter.next(); String[] values = (String[]) requestParams.get(name); String valueStr = ""; for (int i = 0; i < values.length; i++) { valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; } // 乱码解决,这段代码在出现乱码时使用 valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8"); params.put(name, valueStr); } // 验签 boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); // 调用SDK验证签名 // ——请在这里编写您的程序(以下代码仅作参考)—— if (signVerified) { // 商户订单号 String out_trade_no = new String( request.getParameter("out_trade_no").getBytes("ISO-8859-1") , "UTF-8"); // 支付宝交易号 String trade_no = new String( request.getParameter("trade_no").getBytes("ISO-8859-1") , "UTF-8"); // 付款金额 String total_amount = new String( request.getParameter("total_amount").getBytes("ISO-8859-1") , "UTF-8");
// 修改订单号的状态 OrderInfoService orderInfoService = new OrderInfoService(); orderInfoService.updateState(out_trade_no, 2);
request.setAttribute("reuslt", "trade_no:" + trade_no + "<br/>out_trade_no:" + out_trade_no + "<br/>total_amount:" + total_amount); } else { // out.println("验签失败"); request.setAttribute("reuslt", "支付失败"); } } catch (Exception e) { e.printStackTrace(); }
request.getRequestDispatcher("/order/success.jsp").forward(request, response); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}
7、新建两个jsp页面
order/success.jsp和order/alipay.jsp
alipay.jsp
xxxxxxxxxx<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><body>${result}</body><body>
</body></html>success.jsp
xxxxxxxxxx<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><div class="car"> <div class="cont"> <div class="chenggong"> <h3>支付成功</h3> <!--zhifu/--> </div><!--chenggong/--> </div><!--cont/--></div><!--car/--><body>
</body></html>
测试的时候用虚拟买家的账号扫码即可,钱不够可以去页面端充值
Day 5
退出功能
验证码功能
1、导入servlet
下载钉钉群的RandomServlet.java代码到controller包下
2、index.jsp界面
125行左右,注释掉原本的,并新增一行,如下
xxxxxxxxxx<form action="javascript:void(0)"> <input type="text" name="UserName" placeholder="手机号/邮箱/乐购ID"> <biao style="font-size:12px;color:red;width:350px;display:inline-block;margin:3px 0px;margin-left:50px;" id="shouji"> </biao> <input type="password" name="PassWord" placeholder="输入您的密码"> <biao style="font-size:12px;color:red;width:350px;display:inline-block;margin:3px 0px;margin-left:50px;" id="mima"> </biao> <input type="text" name="yzm" placeholder="验证码" id="yzm"> <%--注释掉之前的,并加入新的--%> <%--<span id="idcode">验证码初始化</span>--%> <img src="RandomServlet" onclick="this.src=this.src+'?'+Math.random()" onmouseover="this.style.cursor='hand'" height="40pt"> <biao style="font-size:12px;color:red;width:350px;display:inline-block;margin:3px 0px;margin-left:50px;" id="yz"> </biao> <hang><input type="checkbox" name="gou" id="fws">同意 瑶乐购 服务条款<gou id="gou" style="margin-left:20px;color:red;display:none;">请勾选服务条款</gou><a href="reg1.jsp" target="_blank">注册账号</a></hang> <input type="submit" name = "submit" value="登 录" id="tijiao"> </form>
3、修改IndexServlet的post方法
xxxxxxxxxx protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //处理登录功能 request.setCharacterEncoding("utf-8"); //设置编码 response.setCharacterEncoding("utf-8"); UserService userService = new UserService();
//登录 String name = request.getParameter("UserName"); //从文本框拿到对应数据 String pwd = request.getParameter("PassWord"); String yzm = request.getParameter("yzm"); String true_yzm = (String) request.getSession().getAttribute("random_captcha"); String result = "yzmfalse"; if(true_yzm.equals(yzm) && !yzm.equals(null)) { User user = new User(); user.setUserName(name); user.setPassword(pwd);
//调用service校验账户信息 result = userService.login(user);
if ("true".equals(result)) { //这样写不会报空指针错误 //加载user数据 user = userService.getUserByName(user.getUserName()); //登录成功将用户信息放入user request.getSession(true).setAttribute("user", user); } } //将结果写回客户端,即作为回调函数的参数 PrintWriter out = response.getWriter(); out.write(result); out.flush(); out.close(); }}
4、index.jsp界面
35行左右修改
xxxxxxxxxx $("#tijiao").click(function (){ if (!document.getElementById('fws').checked) { alert('请勾选服务条款协议'); }else { //获取用户名和密码 var UserName = $("[name=UserName]").val(); var PassWord = $("[name=PassWord]").val(); var yzm = $("[name=yzm]").val(); //执行异步请求 $.post("IndexServlet", {"UserName": UserName, "PassWord": PassWord, "yzm": yzm}, function (Data) { if (Data == "true") { //加载页面 window.open("IndexServlet", "_self"); } else if (Data == "yzmfalse") { $("#text").html("验证码错误!"); $("#beijing").fadeIn("300"); } else { $("#beijing").fadeIn("300"); } }) } })
5、RandomServlet.java
50行改-为_
xxxxxxxxxxrequest.getSession().setAttribute("random_captcha", sRand);