想培训和学习的多多关注尚硅谷
尚硅谷官网
尚硅谷2022 javaweb网上书城视频
文档连接
代码地址-请看book-dev分支
环境准备
安装jdk1.8
安装idea
下载tomcat
登陆设置
添加【-parameters】参数
java8新增了一个编译参数-parameters,可以让我们在运行期获取方法参数名称,没有配置获取的是arg0、arg1等,配置后获取正确的方法名和参数
否则controller传值异常
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RE0oDriq-1654307516185)(image/image-20220603094448871.png)]
添加tomcat服务
选择local
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aeei8cW2-1654307516196)(image/image-20220603094720211.png)]
导入本地Tomcat8
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8xXJRO1I-1654307516200)(image/image-20220603095020572.png)]
部署和登录
部署项目
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s1WZN1i1-1654307516205)(image/image-20220603095351130.png)]
登录
登录地址 : 主机:端口/page.do?operate=page&page=user/login
http://localhost:8080/page.do?operate=page&page=user/login
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KrMTxNWX-1654307516206)(image/image-20220603105034944.png)]
网上书城项目
注册请求过程
- 调用com.atguigu.myssm.myspringmvc.DispatcherServlet#service找到控制器
- 通过控制器com.atguigu.book.controller.UserController#regist找到service
- 通过service com.atguigu.book.service.impl.UserServiceImpl#regist找到dao
- com.atguigu.book.dao.impl.UserDAOImpl#addUser
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F9shDnLC-1654307516211)(image/image-20220604091040844.png)]
vue在项目中的使用
导入如下js文件
<script language="JavaScript" th:src="@{/static/script/vue.js}"></script>
<script language="JavaScript" th:src="@{/static/script/axios.min.js}"></script>
js中使用vue
window.onload=function(){
var vue = new Vue({
el:"#cart_div",
data:{
cart:{}
},
methods:{
getCart:function(){
axios({
method:"POST",
url:"cart.do",
params:{
operate:'cartInfo'
}
})
.then(function (value) {
var cart = value.data ;
vue.cart = cart ;
})
.catch(function (reason) { });
},
editCart:function(cartItemId , buyCount){
axios({
method:"POST",
url:"cart.do",
params:{
operate:'editCart',
cartItemId:cartItemId,
buyCount:buyCount
}
})
.then(function (value) {
vue.getCart();
})
.catch(function (reason) { });
}
},
mounted:function(){
debugger;
this.getCart() ;
}
});
}
页面访问和thymeleaf的使用
thymeleaf的使用
https://blog.csdn.net/ityouknow/article/details/52441288
访问index.html页面
访问WEB-INF/pages/index.html,去掉前缀“WEB-INF/pages/”,后缀.html,后台调整加上page.do,
DispatcherServlet#service作用
// 第一步 page.do -> PageController 或者 page ->PageController
// 第二步 operate=page:表示页面跳转, return Page; page=index,返回index
http://localhost:8080/page.do?operate=page&page=index
-
WEB—INF下页面都是受保护的,需要通过后台跳转
1、PageController.java public class PageController { public String page(String page){ return page; // frames/left } } 2、applicationContext.xml <bean id="page" class="com.atguigu.myssm.myspringmvc.PageController"/> 3、web.xml <context-param> <param-name>view-prefix</param-name> <param-value>/WEB-INF/pages/</param-value> </context-param> <context-param> <param-name>view-suffix</param-name> <param-value>.html</param-value> </context-param>
设计框架mvc和三层架构
参考博客
https://blog.csdn.net/QBDBK/article/details/121020659
mvc
- C : controller 控制层
- V:视图成(html,jsp,vue)
- M:模型层(分两种:第一种service,dao业务模型,第二种entity实体类模型)
第一种:
有现成前端页面(类似或者可以借鉴的)
创建项目,导包或配置maven,基本框架搭建的工作准备(实体,工具类,配置文件)
V:前端视图
C:servlet
M:service(serviceimp)
M:dao(daoimp)
M:entity
第二种:
没有可借鉴的页面
创建项目,导包或配置maven,基本框架搭建的工作准备(实体,工具类,配置文件)
C:servlet
M:service(serviceimp)
M:dao(daoimp)
M:entity
V:前端视图
实现步骤
注册功能实现
参数验证
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4xtW0fw9-1654307516213)(image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzU2NTIyNTc0,size_16,color_FFFFFF,t_70-16542202621096.png)]
验证用户名是否合法:5-12位,由数字,字母或下划线组成
验证密码是否合法:5-12位,由数字,字母或下划线组成
验证确认密码和密码是否相同
验证电子邮件是否合法:
验证验证码是否非空:该阶段暂不用实现验证码的正确性判断
//用户名不能为空,而且是6~16位数字和字母组成
var unameReg = /[0-9a-zA-Z]{6,16}/;
var unameTxt = $("unameTxt");
var uname = unameTxt.value ;
var unameSpan = $("unameSpan");
if(!unameReg.test(uname)){
unameSpan.style.visibility="visible";
return false ;
}else{
unameSpan.style.visibility="hidden";
}
//密码的长度至少为8位
var pwdTxt = $("pwdTxt");
var pwd = pwdTxt.value ;
var pwdReg = /[\w]{8,}/; // /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,}$/;
var pwdSpan = $("pwdSpan");
if(!pwdReg.test(pwd)){
pwdSpan.style.visibility="visible";
return false ;
}else{
pwdSpan.style.visibility="hidden";
}
//密码两次输入不一致
var pwd2 = $("pwdTxt2").value ;
var pwdSpan2 = $("pwdSpan2") ;
if(pwd2!=pwd){
pwdSpan2.style.visibility="visible";
return false ;
}else{
pwdSpan2.style.visibility="hidden";
}
//请输入正确的邮箱格式
var email = $("emailTxt").value ;
var emailSpan = $("emailSpan");
var emailReg = /^[a-zA-Z0-9_\.-]+@([a-zA-Z0-9-]+[\.]{1})+[a-zA-Z]+$/;
if(!emailReg.test(email)){
emailSpan.style.visibility="visible";
return false ;
}else{
emailSpan.style.visibility="hidden";
}
编写数据库表中对应的javaBean对象——User类
public class User {
private Integer id ;
private String uname ;
private String pwd ;
private String email;
private Integer role = 0 ;
private Cart cart ;
private List<OrderBean> orderList ;
// -- 省略set/get
编写工具类ConnUtil.java
ConnUtil.java
public class ConnUtil {
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
//private static ThreadLocal<Object> threadLocal2 = new ThreadLocal<>();
//private static ThreadLocal<Object> threadLocal3 = new ThreadLocal<>();
public static final String DRIVER = "com.mysql.jdbc.Driver" ;
public static final String URL = "jdbc:mysql://localhost:3306/bookdb?useUnicode=true&characterEncoding=utf-8&useSSL=false";
public static final String USER = "root";
public static final String PWD = "root" ;
private static Connection createConn(){
try {
//1.加载驱动
Class.forName(DRIVER);
//2.通过驱动管理器获取连接对象
return DriverManager.getConnection(URL, USER, PWD);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return null ;
}
public static Connection getConn(){
Connection conn = threadLocal.get();
if(conn==null){
conn =createConn();
threadLocal.set(conn);
}
return threadLocal.get() ;
}
public static void closeConn() throws SQLException {
Connection conn = threadLocal.get();
if(conn==null){
return ;
}
if(!conn.isClosed()){
conn.close();
//threadLocal.set(null);
threadLocal.remove();
}
}
}
编写 BaseDao和与负责数据库交互的Dao
BaseDao类
package com.atguigu.myssm.basedao;
import java.lang.reflect.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public abstract class BaseDAO<T> {
protected Connection conn ;
protected PreparedStatement psmt ;
protected ResultSet rs ;
//T的Class对象
private Class entityClass ;
public BaseDAO() {
//getClass() 获取Class对象,当前我们执行的是new FruitDAOImpl() , 创建的是FruitDAOImpl的实例
//那么子类构造方法内部首先会调用父类(BaseDAO)的无参构造方法
//因此此处的getClass()会被执行,但是getClass获取的是FruitDAOImpl的Class
//所以getGenericSuperclass()获取到的是BaseDAO的Class
Type genericType = getClass().getGenericSuperclass();
//ParameterizedType 参数化类型
Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
//获取到的<T>中的T的真实的类型
Type actualType = actualTypeArguments[0];
try {
entityClass = Class.forName(actualType.getTypeName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new DAOException("BaseDAO 构造方法出错了,可能的原因是没有指定<>中的类型");
}
}
protected Connection getConn(){
return ConnUtil.getConn();
}
protected void close(ResultSet rs , PreparedStatement psmt , Connection conn){
}
//给预处理命令对象设置参数
private void setParams(PreparedStatement psmt , Object... params) throws SQLException {
if(params!=null && params.length>0){
for (int i = 0; i < params.length; i++) {
psmt.setObject(i+1,params[i]);
}
}
}
//执行更新,返回影响行数
protected int executeUpdate(String sql , Object... params) {
boolean insertFlag = false ;
insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
conn = getConn();
try{
if(insertFlag){
psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
}else {
psmt = conn.prepareStatement(sql);
}
setParams(psmt,params);
int count = psmt.executeUpdate() ;
if(insertFlag){
rs = psmt.getGeneratedKeys();
if(rs.next()){
return ((Long)rs.getLong(1)).intValue();
}
}
return 0 ;
}catch (SQLException e){
e.printStackTrace();
throw new DAOException("BaseDAO executeUpdate出错了");
}
}
//通过反射技术给obj对象的property属性赋propertyValue值
private void setValue(Object obj , String property , Object propertyValue) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
Class clazz = obj.getClass();
//获取property这个字符串对应的属性名 , 比如 "fid" 去找 obj对象中的 fid 属性
Field field = clazz.getDeclaredField(property);
if(field!=null){
//获取当前字段的类型名称
String typeName = field.getType().getName();
//判断如果是自定义类型,则需要调用这个自定义类的带一个参数的构造方法,创建出这个自定义的实例对象,然后将实例对象赋值给这个属性
if(isMyType(typeName)){
//假设typeName是"com.atguigu.qqzone.pojo.UserBasic"
Class typeNameClass = Class.forName(typeName);
Constructor constructor = typeNameClass.getDeclaredConstructor(Integer.class);
propertyValue = constructor.newInstance(propertyValue);
}
field.setAccessible(true);
field.set(obj,propertyValue);
}
}
private static boolean isNotMyType(String typeName){
return "java.lang.Integer".equals(typeName)
|| "java.lang.String".equals(typeName)
|| "java.util.Date".equals(typeName)
|| "java.lang.Double".equals(typeName)
|| "java.sql.Date".equals(typeName);
}
private static boolean isMyType(String typeName){
return !isNotMyType(typeName);
}
//执行复杂查询,返回例如统计结果
protected Object[] executeComplexQuery(String sql , Object... params){
conn = getConn() ;
try{
psmt = conn.prepareStatement(sql);
setParams(psmt,params);
rs = psmt.executeQuery();
//通过rs可以获取结果集的元数据
//元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等
ResultSetMetaData rsmd = rs.getMetaData();
//获取结果集的列数
int columnCount = rsmd.getColumnCount();
Object[] columnValueArr = new Object[columnCount];
//6.解析rs
if(rs.next()){
for(int i = 0 ; i<columnCount;i++){
Object columnValue = rs.getObject(i+1); //33 苹果 5
columnValueArr[i]=columnValue;
}
return columnValueArr ;
}
}catch(SQLException e){
e.printStackTrace();
throw new DAOException("BaseDAO executeComplexQuery出错了");
}
return null ;
}
//执行查询,返回单个实体对象
protected T load(String sql , Object... params){
conn = getConn() ;
try{
psmt = conn.prepareStatement(sql);
setParams(psmt,params);
rs = psmt.executeQuery();
//通过rs可以获取结果集的元数据
//元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等
ResultSetMetaData rsmd = rs.getMetaData();
//获取结果集的列数
int columnCount = rsmd.getColumnCount();
//6.解析rs
if(rs.next()){
T entity = (T)entityClass.newInstance();
for(int i = 0 ; i<columnCount;i++){
String columnName = rsmd.getColumnName(i+1); //fid fname price
Object columnValue = rs.getObject(i+1); //33 苹果 5
setValue(entity,columnName,columnValue);
}
return entity ;
}
}catch (Exception e){
e.printStackTrace();
throw new DAOException("BaseDAO load出错了");
}
return null ;
}
//执行查询,返回List
protected List<T> executeQuery(String sql , Object... params){
List<T> list = new ArrayList<>();
conn = getConn() ;
try{
psmt = conn.prepareStatement(sql);
setParams(psmt,params);
rs = psmt.executeQuery();
//通过rs可以获取结果集的元数据
//元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等
ResultSetMetaData rsmd = rs.getMetaData();
//获取结果集的列数
int columnCount = rsmd.getColumnCount();
//6.解析rs
while(rs.next()){
T entity = (T)entityClass.newInstance();
for(int i = 0 ; i<columnCount;i++){
String columnName = rsmd.getColumnLabel(i+1); //fid fname price
Object columnValue = rs.getObject(i+1); //33 苹果 5
// System.out.println("columnName==>"+columnName+",columnValue=>"+columnValue);
setValue(entity,columnName,columnValue);
}
list.add(entity);
}
}catch (Exception e){
e.printStackTrace();
throw new DAOException("BaseDAO executeQuery出错了");
}
return list ;
}
}
UserDao.java
package com.atguigu.book.dao;
import com.atguigu.book.pojo.User;
public interface UserDAO {
User getUser(String uname , String pwd );
void addUser(User user);
User getUser(String uname);
}
UserDaoImpl类,继承了BaseDao实现了UserDao类
package com.atguigu.book.dao.impl;
import com.atguigu.book.dao.UserDAO;
import com.atguigu.book.pojo.User;
import com.atguigu.myssm.basedao.BaseDAO;
public class UserDAOImpl extends BaseDAO<User> implements UserDAO {
@Override
public User getUser(String uname, String pwd) {
return load("select * from t_user where uname like ? and pwd like ? " , uname , pwd );
}
@Override
public void addUser(User user) {
executeUpdate("insert into t_user values(0,?,?,?,0)",user.getUname(),user.getPwd(),user.getEmail()) ;
}
@Override
public User getUser(String uname) {
return load("select * from t_user where uname = ?" , uname);
}
}
编写Service层
package com.atguigu.book.service;
import com.atguigu.book.pojo.User;
public interface UserService {
User login(String uname , String pwd );
void regist(User user);
User getUser(String uname);
}
具体实现类UserServiceImpl
package com.atguigu.book.service.impl;
import com.atguigu.book.dao.UserDAO;
import com.atguigu.book.pojo.User;
import com.atguigu.book.service.UserService;
public class UserServiceImpl implements UserService {
private UserDAO userDAO ;
@Override
public User login(String uname, String pwd) {
return userDAO.getUser(uname,pwd);
}
@Override
public void regist(User user) {
userDAO.addUser(user);
}
@Override
public User getUser(String uname) {
return userDAO.getUser(uname);
}
}
编写web层(servlet)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6HUXWSq1-1654307516216)(image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Vkd2FyZHd6dw==,size_16,color_FFFFFF,t_70.png)]
ViewBaseServlet
package com.atguigu.myssm.myspringmvc;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ViewBaseServlet extends HttpServlet {
private TemplateEngine templateEngine;
@Override
public void init() throws ServletException {
// 1.获取ServletContext对象
ServletContext servletContext = this.getServletContext();
// 2.创建Thymeleaf解析器对象
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
// 3.给解析器对象设置参数
// ①HTML是默认模式,明确设置是为了代码更容易理解
templateResolver.setTemplateMode(TemplateMode.HTML);
// ②设置前缀
String viewPrefix = servletContext.getInitParameter("view-prefix");
templateResolver.setPrefix(viewPrefix);
// ③设置后缀
String viewSuffix = servletContext.getInitParameter("view-suffix");
templateResolver.setSuffix(viewSuffix);
// ④设置缓存过期时间(毫秒)
templateResolver.setCacheTTLMs(60000L);
// ⑤设置是否缓存
templateResolver.setCacheable(true);
// ⑥设置服务器端编码方式
templateResolver.setCharacterEncoding("utf-8");
// 4.创建模板引擎对象
templateEngine = new TemplateEngine();
// 5.给模板引擎对象设置模板解析器
templateEngine.setTemplateResolver(templateResolver);
}
protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 1.设置响应体内容类型和字符集
resp.setContentType("text/html;charset=UTF-8");
// 2.创建WebContext对象
WebContext webContext = new WebContext(req, resp, getServletContext());
// 3.处理模板数据
templateEngine.process(templateName, webContext, resp.getWriter());
}
}
package com.atguigu.myssm.myspringmvc;
import com.atguigu.myssm.ioc.BeanFactory;
import com.atguigu.myssm.util.StringUtil;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet{
private BeanFactory beanFactory ;
public DispatcherServlet(){
}
public void init() throws ServletException {
super.init();
//之前是在此处主动创建IOC容器的
//现在优化为从application作用域去获取
//beanFactory = new ClassPathXmlApplicationContext();
ServletContext application = getServletContext();
Object beanFactoryObj = application.getAttribute("beanFactory");
if(beanFactoryObj!=null){
beanFactory = (BeanFactory)beanFactoryObj ;
}else{
throw new RuntimeException("IOC容器获取失败!");
}
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置编码
//request.setCharacterEncoding("UTF-8");
//假设url是: http://localhost:8080/pro15/hello.do
//那么servletPath是: /hello.do
// 我的思路是:
// 第1步: /hello.do -> hello 或者 /fruit.do -> fruit
// 第2步: hello -> HelloController 或者 fruit -> FruitController
String servletPath = request.getServletPath();
servletPath = servletPath.substring(1);
int lastDotIndex = servletPath.lastIndexOf(".do") ;
servletPath = servletPath.substring(0,lastDotIndex);
Object controllerBeanObj = beanFactory.getBean(servletPath);
String operate = request.getParameter("operate");
if(StringUtil.isEmpty(operate)){
operate = "index" ;
}
try {
Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
for(Method method : methods){
if(operate.equals(method.getName())){
//1.统一获取请求参数
//1-1.获取当前方法的参数,返回参数数组
Parameter[] parameters = method.getParameters();
//1-2.parameterValues 用来承载参数的值
Object[] parameterValues = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
String parameterName = parameter.getName() ;
if("arg0".equals(parameterName)){
parameterName = method.getName();
}
//如果参数名是request,response,session 那么就不是通过请求中获取参数的方式了
if("request".equals(parameterName)){
parameterValues[i] = request ;
}else if("response".equals(parameterName)){
parameterValues[i] = response ;
}else if("session".equals(parameterName)){
parameterValues[i] = request.getSession() ;
}else{
//从请求中获取参数值
String parameterValue = request.getParameter(parameterName);
String typeName = parameter.getType().getName();
Object parameterObj = parameterValue ;
if(parameterObj!=null) {
if ("java.lang.Integer".equals(typeName)) {
parameterObj = Integer.parseInt(parameterValue);
}
}
parameterValues[i] = parameterObj ;
}
}
//2.controller组件中的方法调用
method.setAccessible(true);
Object returnObj = method.invoke(controllerBeanObj,parameterValues);
//3.视图处理
String methodReturnStr = (String)returnObj ;
if(StringUtil.isEmpty(methodReturnStr)){
return ;
}
if(methodReturnStr.startsWith("redirect:")){ //比如: redirect:fruit.do
String redirectStr = methodReturnStr.substring("redirect:".length());
response.sendRedirect(redirectStr);
}else if(methodReturnStr.startsWith("json:")){
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
String jsonStr = methodReturnStr.substring("json:".length());
PrintWriter out = response.getWriter();
out.print(jsonStr);
out.flush();
}else{
super.processTemplate(methodReturnStr,request,response); // 比如: "edit"
}
}
}
/*
}else{
throw new RuntimeException("operate值非法!");
}
*/
} catch (Exception e) {
e.printStackTrace();
throw new DispatcherServletException("DispatcherServlet出错了...");
}
}
}
// 常见错误: IllegalArgumentException: argument type mismatch
UserServet类:用于实现用户登录,用户注册等功能
package com.atguigu.web;
import com.atguigu.pojo.User;
import com.atguigu.service.UserService;
import com.atguigu.service.impl.UserServiceImpl;
import com.atguigu.utils.WebUtils;
import com.google.gson.Gson;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import static com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY;
public class UserServlet extends BaseServlet {
private UserService userService=new UserServiceImpl();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String action = req.getParameter("action");
try {
Method method = this.getClass().getDeclaredMethod(action,
HttpServletRequest.class,HttpServletResponse.class);
method.invoke(this,req,resp);
} catch (Exception e) {
e.printStackTrace();
}
}
protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username=req.getParameter("username");
String password=req.getParameter("password");
User login = userService.login(new User(null, username, password, null));
if(login!=null){
//System.out.println("登陆成功!");
req.getSession().setAttribute("user",login);
req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req,resp);
}else{
//System.out.println("用户名或密码错误!");
//把错误信息,和回显的表单项信息,保存到Request域中
req.setAttribute("msg","用户名或密码错误!");
req.setAttribute("username",username);
req.getRequestDispatcher("/pages/user/login.jsp").forward(req,resp);
}
}
protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取Session中的验证码
String token =(String)req.getSession().getAttribute(KAPTCHA_SESSION_KEY);
//删除Session中的验证码
req.getSession().removeAttribute(KAPTCHA_SESSION_KEY);
//1.获取请求的参数。比如用户名密码邮箱验证码等
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
String code = req.getParameter("code");
User user= WebUtils.copyParamToBean(req.getParameterMap(),new User());
//2.检查验证码是否正确
if(token!=null&&token.equalsIgnoreCase(code)){
// 正确 3检查用户名是否可用
if(userService.existsUsername(username)){
//不可用 跳转到注册页面
//System.out.println("用户名"+username+"已存在!");
req.setAttribute("msg","用户名已存在");
req.setAttribute("username",username);
req.setAttribute("email",email);
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp);
}else{
//可用 调用Service保存到数据库,跳转到登陆成功页面
userService.registUser(user);
req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req,resp);
}
}else{
// 不正确 跳回注册页面
req.setAttribute("msg","验证码错误!");
req.setAttribute("username",username);
req.setAttribute("email",email);
//System.out.println("验证码["+code+"]错误");
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp);
}
}
/*
注销用户
*/
protected void logout(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.销毁Session中的用户登陆信息
//2.重定向到首页
req.getSession().invalidate();
resp.sendRedirect(req.getContextPath());
}
/*
*/
protected void ajaxExistsUsername(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求的参数username
String username = req.getParameter("username");
//调用userservice.existsUsername();
boolean existsUsername = userService.existsUsername(username);
//把返回的结果封装成map对象
Map<String,Object> resultMap=new HashMap<>();
resultMap.put("existsUsername",existsUsername);
Gson gson = new Gson();
String json = gson.toJson(resultMap);
resp.getWriter().write(json);
}
}
第三阶段:编写html页面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>尚硅谷会员注册页面</title>
<link type="text/css" rel="stylesheet" th:href="@{/static/css/style.css}" />
<link rel="stylesheet" th:href="@{/static/css/register.css}"/>
<style type="text/css">
.login_form {
height: 420px;
margin-top: 25px;
}
</style>
<script language="JavaScript" th:src="@{/static/script/regist.js}"></script>
</head>
<body>
<div id="login_header">
<a href="../index.html">
<img class="logo_img" alt="" th:src="@{/static/img/logo.gif}" />
</a>
</div>
<div class="login_banner">
<div class="register_form">
<h1>注册尚硅谷会员</h1>
<form th:action="@{/user.do}" method="post" onsubmit="return preRegist() ;">
<input type="hidden" name="operate" value="regist"/>
<div class="form-item">
<div>
<label>用户名称:</label>
<input id="unameTxt" type="text" placeholder="请输入用户名" name="uname" value="hello2022" onblur="ckUname(this.value)"/>
</div>
<span id="unameSpan" class="errMess">用户名应为6~16位数字和字母组成</span>
</div>
<div class="form-item">
<div>
<label>用户密码:</label>
<input id="pwdTxt" type="password" placeholder="请输入密码" name="pwd" value="ok"/>
</div>
<span id="pwdSpan" class="errMess">密码的长度至少为8位</span>
</div>
<div class="form-item">
<div>
<label>确认密码:</label>
<input id="pwdTxt2" type="password" placeholder="请输入确认密码" value="ok"/>
</div>
<span id="pwdSpan2" class="errMess">密码两次输入不一致</span>
</div>
<div class="form-item">
<div>
<label>用户邮箱:</label>
<input id="emailTxt" type="text" placeholder="请输入邮箱" name="email" value="bao@126.com"/>
</div>
<span id="emailSpan" class="errMess">请输入正确的邮箱格式</span>
</div>
<div class="form-item">
<div>
<label>验证码:</label>
<div class="verify">
<input type="text" name="verifyCode" placeholder="" />
<img th:src="@{/kaptch.jpg}" alt="" />
</div>
</div>
<span class="errMess">请输入正确的验证码</span>
</div>
<button class="btn">注册</button>
</form>
</div>
</div>
<div id="bottom">
<span>
尚硅谷书城.Copyright ©2015
</span>
</div>
</body>
</html>
编写js
function $(id){
return document.getElementById(id);
}
function preRegist(){
//用户名不能为空,而且是6~16位数字和字母组成
var unameReg = /[0-9a-zA-Z]{6,16}/;
var unameTxt = $("unameTxt");
var uname = unameTxt.value ;
var unameSpan = $("unameSpan");
if(!unameReg.test(uname)){
unameSpan.style.visibility="visible";
return false ;
}else{
unameSpan.style.visibility="hidden";
}
//密码的长度至少为8位
var pwdTxt = $("pwdTxt");
var pwd = pwdTxt.value ;
var pwdReg = /[\w]{8,}/; // /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,}$/;
var pwdSpan = $("pwdSpan");
if(!pwdReg.test(pwd)){
pwdSpan.style.visibility="visible";
return false ;
}else{
pwdSpan.style.visibility="hidden";
}
//密码两次输入不一致
var pwd2 = $("pwdTxt2").value ;
var pwdSpan2 = $("pwdSpan2") ;
if(pwd2!=pwd){
pwdSpan2.style.visibility="visible";
return false ;
}else{
pwdSpan2.style.visibility="hidden";
}
//请输入正确的邮箱格式
var email = $("emailTxt").value ;
var emailSpan = $("emailSpan");
var emailReg = /^[a-zA-Z0-9_\.-]+@([a-zA-Z0-9-]+[\.]{1})+[a-zA-Z]+$/;
if(!emailReg.test(email)){
emailSpan.style.visibility="visible";
return false ;
}else{
emailSpan.style.visibility="hidden";
}
return true ;
}
//如果想要发送异步请求,我们需要一个关键的对象 XMLHttpRequest
var xmlHttpRequest ;
function createXMLHttpRequest(){
if(window.XMLHttpRequest){
//符合DOM2标准的浏览器 ,xmlHttpRequest的创建方式
xmlHttpRequest = new XMLHttpRequest() ;
}else if(window.ActiveXObject){//IE浏览器
try{
xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}catch (e) {
xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP")
}
}
}
function ckUname(uname){
createXMLHttpRequest();
var url = "user.do?operate=ckUname&uname="+uname ;
xmlHttpRequest.open("GET",url,true);
//设置回调函数
xmlHttpRequest.onreadystatechange = ckUnameCB ;
//发送请求
xmlHttpRequest.send();
}
function ckUnameCB(){
if(xmlHttpRequest.readyState==4 && xmlHttpRequest.status==200){
//xmlHttpRequest.responseText 表示 服务器端响应给我的文本内容
//alert(xmlHttpRequest.responseText);
var responseText = xmlHttpRequest.responseText ;
// {'uname':'1'}
//alert(responseText);
if(responseText=="{'uname':'1'}"){
alert("用户名已经被注册!");
}else{
alert("用户名可以注册!");
}
}
}