【JavaWeb学习笔记】19 - 网购家居项目开发(上)

news2024/11/19 7:33:38

一、项目开发流程

程序框架图

项目具体分层方案

MVC

1、说明是MVC

MVC全称: Mode模型、View视图、Controller控制器。

MVC最早出现在JavaEE三层中的Web层,它可以有效的指导WEB层的代码如何有效分离,单独工作。

View视图:只负责数据和界面的显示,不接受任何与显示数据无关的代码,便于程序员和美工的分工(Vue/JSP/Thymeleaf/HTML)

Controller控制器:只负责接收请求,调用业务层的代码处理请求,然后派发页面,是一个"调度者"的角色(Servlet)

Model模型:将与业务逻辑相关的数据封装为具体的JavaBean类,其中不掺杂任何与数据处理相关的代码(JavaBean/Domain/Pojo)

2、MVC是一种思想

MVC的理念是将软件代码拆分成为组件,单独开发,组合使用(目的还是为了解耦合) ,也有很多落地的框架比如SpringMVC

二、实现1 正确加载静态页面

前端人员给的静态页面

三、实现功能02 会员注册前端JS校验

1.验证用户名:必须字母,数字下划线组成,并且长度为6到10位 => JQuery + 正则表达式

2.验证密码:必须由字母,数字下划线组成,并且长度为6到10位

3.邮箱格式验证:常规验证即可

4.验证码:后面实现

    <script type="text/javascript" src = "../../script/jquery-3.6.0.min.js"></script>
    <script>
        $(function () {//页面加载完成后执行function

            //绑定点击事件
            $("#sub-btn").click(function (){

                //获取输入的用户名 => 自己看前端给的页面
                var $userName = $("#username").val();
                // alert("usernameVal = " + $userName)
                //使用正则表达式进行验证
                var usernamePattern = /^\w{6,10}$/;
                if(!usernamePattern.test($userName)){
                    //查看前端给的代码是否有错误提示信息
                    // <span class="errorMsg"
                          // style="float: right; font-weight: bold; font-size: 20pt; margin-left: 10px;"></span>
                    //jquery的属性过滤器
                    $("span[class = 'errorMsg']").text("用户格式不对 需要6-10字符");
                    return false;//不提交 需要返回false 不返回false会导致页面跳转
                }
                var password = $("#password").val();
                var passwordPattern = /^\w{6,10}$/;
                if(!passwordPattern.test(password)){
                    //jquery的基本过滤器
                    $("span.errorMsg").text("密码格式不对 需要6-10字符");
                    return false;
                }
                //验证两次密码是否正确
                var repwd = $("#repwd").val();
                if(repwd != password){
                    $("span.errorMsg").text("输入的两次密码不同");
                    return false;
                }
                var email = $("#email").val();
                var emailPattern = /^[\w-]+@([a-zA-Z]+\.)+[a-zA-Z]+$/;
                if(!emailPattern.test(email)){
                    $("span[class = 'errorMsg']").text("电子邮件格式不对");
                    return false;
                }
                //到这里就全部过关 => 我们暂时不提交
                $("span.errorMsg").text("验证通过");
                return false;
            })
        })
    </script>

四、实现功能03 - 会员注册后端

导入mhl使用的BasicDAO以及JDBCbyDruid 测试是否成功

BasicDAO

package com.yinhai.furns.dao;


import com.yinhai.furns.utils.JDBCUtilsByDruid;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

/**
 * @author 韩顺平
 * @version 1.0
 * 开发BasicDAO , 是其他DAO的父类
 */
public class BasicDAO<T> { //泛型指定具体类型

    private QueryRunner qr =  new QueryRunner();

    //开发通用的dml方法, 针对任意的表
    public int update(String sql, Object... parameters) {

        Connection connection = null;

        try {
            //这里从数据库连接池获取connection
            //老师说明: 每次从连接池中取出Connection , 不能保证是同一个
            //1.我们目前已经是从当前线程关联的ThreadLocal获取的connection
            //2.所以我们可以保证是同一个连接(在同一个线程/同一个请求)
            connection = JDBCUtilsByDruid.getConnection();
            int update = qr.update(connection, sql, parameters);
            return  update;
        } catch (SQLException e) {
           throw  new RuntimeException(e); //将编译异常->运行异常 ,抛出
        }

    }

    //返回多个对象(即查询的结果是多行), 针对任意表

    /**
     *
     * @param sql sql 语句,可以有 ?
     * @param clazz 传入一个类的Class对象 比如 Actor.class
     * @param parameters 传入 ? 的具体的值,可以是多个
     * @return 根据Actor.class 返回对应的 ArrayList 集合
     */
    public List<T> queryMulti(String sql, Class<T> clazz, Object... parameters) {

        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return qr.query(connection, sql, new BeanListHandler<T>(clazz), parameters);

        } catch (SQLException e) {
            throw  new RuntimeException(e); //将编译异常->运行异常 ,抛出
        }

    }

    //查询单行结果 的通用方法
    public T querySingle(String sql, Class<T> clazz, Object... parameters) {

        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return  qr.query(connection, sql, new BeanHandler<T>(clazz), parameters);

        } catch (SQLException e) {
            throw  new RuntimeException(e); //将编译异常->运行异常 ,抛出
        }
    }

    //查询单行单列的方法,即返回单值的方法

    public Object queryScalar(String sql, Object... parameters) {

        Connection connection = null;
        try {
            connection = JDBCUtilsByDruid.getConnection();
            return  qr.query(connection, sql, new ScalarHandler(), parameters);

        } catch (SQLException e) {
            throw  new RuntimeException(e); //将编译异常->运行异常 ,抛出
        } 
    }

}

JDBC工具类 

package com.yinhai.furns.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * @author 韩顺平
 * @version 1.0
 * 基于druid数据库连接池的工具类
 */
public class JDBCUtilsByDruid {

    private static DataSource ds;
    //定义属性ThreadLocal, 这里存放一个Connection
    private static ThreadLocal<Connection> threadLocalConn =
            new ThreadLocal<>();

    //在静态代码块完成 ds初始化
    static {
        Properties properties = new Properties();
        try {
            //因为我们是web项目,他的工作目录在out, 文件的加载,需要使用类加载器
            //找到我们的工作目录
            properties.load(JDBCUtilsByDruid.class.getClassLoader()
                    .getResourceAsStream("druid.properties"));
            //properties.load(new FileInputStream("src\\druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //编写getConnection方法
    //public static Connection getConnection() throws SQLException {
    //    return ds.getConnection();
    //}

    /**
     * 从ThreadLocal获取connection, 从而保证在同一个线程中,
     * 获取的是同一个Connection
     * @return
     * @throws SQLException
     */
    public static Connection getConnection()  {

        Connection connection = threadLocalConn.get();
        if (connection == null) {//说明当前的threadLocalConn没有连接
            //就从数据库连接池中,取出一个连接放入, threadLocalConn
            try {
                connection = ds.getConnection();
                //将连接设置为手动提交, 即不要自动提交
                connection.setAutoCommit(false);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            threadLocalConn.set(connection);

        }
        return connection;
    }

    /**
     * 提交事务, java基础 mysql事务+线程+过滤器机制+ThreadLocal
     */
    public static  void commit() {

        Connection connection = threadLocalConn.get();
        if(connection != null) {//确保该连接是有效

            try {
                connection.commit();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } finally {
                try {
                    connection.close();//关闭连接
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }

        //老师说明
        //1. 当提交后,需要把connection从 threadLocalConn 清除掉
        //2. 不然,会造成 threadLocalConn 长时间持有该连接, 会影响效率
        //3. 也因为我们Tomcat底层使用的是线程池技术
        threadLocalConn.remove();

    }

    /**
     * 老师说明:  所谓回滚,是回滚/撤销和 connection管理的操作删掉,修改,添加
     */
    public static  void rollback() {

        Connection connection = threadLocalConn.get();
        if(connection != null) {//保证当前的连接是有效

            try {
                connection.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } finally {
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }

        threadLocalConn.remove();
    }



    //关闭连接, 老师再次强调: 在数据库连接池技术中,close 不是真的断掉连接
    //而是把使用的Connection对象放回连接池
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {

        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

实现Member的功能 查询等

一个规范接口

package com.yinhai.furns.dao;

import  com.yinhai.furns.javabean.Member;

/**
 * @author 银小海
 * @version 1.0
 * @email yinhai14@qq.com
 */
public interface MemberDAO {

    //小伙伴要自己分析,需要哪些方法
    //提供一个通过用户名返回对应的Member
    public Member queryMemberByUsername(String username);

    //提供一个保存Member对象到数据库/表member表
    public int saveMember(Member member);

    /**
     * 根据用户名和密码返回Member
     * @param username 用户名
     * @param password 密码
     * @return 返回的对象,如果不存在,返回null
     *
     */
    public Member queryMemberByUsernameAndPassword
    (String username, String password);
}

实现Member的功能 查询 添加等 

package com.yinhai.furns.dao.impl;

import com.yinhai.furns.dao.BasicDAO;
import com.yinhai.furns.dao.MemberDAO;

import  com.yinhai.furns.javabean.Member;


/**
 * @author 银小海
 * @version 1.0
 * @email yinhai14@qq.com
 */
public class MemberDAOImpl extends BasicDAO<Member> implements MemberDAO {
    /**
     * 通过用户名返回对应的Member
     *
     * @param username 用户名
     * @return 对应的Member, 如果没有该Member, 返回 null
     */
    @Override
    public Member queryMemberByUsername(String username) {
        //老师提示,sql 先在sqlyog 测试,然后再拿到程序中
        //这里可以提高我们的开发效率,减少不必要的bug
        String sql = "SELECT `id`,`username`,`password`,`email` FROM `member`\n" +
                "WHERE `username` = ?";
        return querySingle(sql, Member.class, username);
    }

    /**
     * 保存一个会员
     *
     * @param member 传入Member对象
     * @return 返回-1 就是失败,返回其它的数字就是受影响的行数
     */
    @Override
    public int saveMember(Member member) {
        String sql = "INSERT INTO `member`(`username`,`password`,`email`) " +
                " VALUES(?,MD5(?), ?)";
        return update(sql, member.getUsername(),
                member.getPassword(), member.getEmail());
    }

    @Override
    public Member queryMemberByUsernameAndPassword(String username, String password) {

        String sql = "SELECT `id`,`username`,`password`,`email` FROM `member` " +
                " WHERE `username`=? and `password`=md5(?)";
        return querySingle(sql, Member.class, username, password);
    }


}

测试 

package com.yinhai.furns.test;

import com.yinhai.furns.dao.MemberDAO;
import com.yinhai.furns.dao.impl.MemberDAOImpl;
import com.yinhai.furns.javabean.Member;

/**
 * @author 银小海
 * @version 1.0
 * @email yinhai14@qq.com
 */
public class MemberTest {
    public static void main(String[] args) {
        MemberDAO memberDAO = new MemberDAOImpl();
        if (memberDAO.queryMemberByUsername("admin") == null){
            System.out.println("null");
        }else {
            System.out.println("exist");
        }
        Member member = new Member(null,"jack","jack","135465@qq.com");
        if(memberDAO.saveMember(member) == 0){
            System.out.println("添加失败");
        }else{
            System.out.println("添加成功");
        }
    }
}

服务端 提供注册

package com.yinhai.furns.test;

import com.yinhai.furns.javabean.Member;
import com.yinhai.furns.service.MemberService;
import com.yinhai.furns.service.impl.MemberServiceImpl;
import com.yinhai.furns.utils.JDBCUtilsByDruid;
import org.junit.jupiter.api.Test;

/**
 * @author 银小海
 * @version 1.0
 * @email yinhai14@qq.com
 */
public class MemberServiceTest {
    public static void main(String[] args) {
        MemberService memberService = new MemberServiceImpl();
        if (memberService.isExistsUsername("admin")){
            System.out.println("用户存在");
        }else{
            System.out.println("用户不存在");
        }
    }
    @Test
    public void test(){
        Member member = new Member(null, "tom", "tom", "643013242@qq.com");
        MemberService memberService = new MemberServiceImpl();
        boolean b = memberService.registerMember(member);
        if (b){
            System.out.println("注册成功");
        }else{
            System.out.println("注册失败");
        }
        JDBCUtilsByDruid.commit();
    }
}

 一个Servlet提供前后端交流

注册成功 请求转发到注册完成的页面

package com.yinhai.furns.web;

import com.yinhai.furns.javabean.Member;
import com.yinhai.furns.service.MemberService;
import com.yinhai.furns.service.impl.MemberServiceImpl;
import com.yinhai.furns.utils.JDBCUtilsByDruid;

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;

/**
 * @author 银小海
 * @version 1.0
 * @email yinhai14@qq.com
 */
@WebServlet(name = "RegisterServlet",urlPatterns = "/registerServlet")
public class RegisterServlet extends HttpServlet {
    private MemberService memberService = new MemberServiceImpl();
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("user-name");
        String password = request.getParameter("user-password");
        String email = request.getParameter("user-email");
        if(!memberService.isExistsUsername(username)){
            System.out.println(username + "用户可用" + password + email);
            Member member = new Member(null,username,password,email);
            if (memberService.registerMember(member)) {
                request.getRequestDispatcher("/views/member/register_ok.jsp").forward(request,response);
                JDBCUtilsByDruid.commit();
            }else {
                request.getRequestDispatcher("/views/member/login_ok.jsp").forward(request,response);
            }
        }else{
            // System.out.println("用户不存在 返回注册页面");
            request.getRequestDispatcher("/views/member/register_fail.jsp").forward(request,response);
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}

五、实现功能04-会员登录

1.输入用户名、密码后提交

2.判断会员是否存在

3.会员存在(数据库),显示登录成功页面

在DAO类编写对数据库操作 也需要在父类以及接口内写该方法

public class MemberDAOImpl extends BasicDAO<Member> implements MemberDAO {
    @Override
    public Member queryMemberByUsernameAndPassword(String username, String password) {

        String sql = "SELECT `id`,`username`,`password`,`email` FROM `member` " +
                " WHERE `username`=? and `password`=md5(?)";
        return querySingle(sql, Member.class, username, password);
    }


}

 在Service调用该方法

public class MemberServiceImpl implements MemberService {
    @Override
    public Member login(Member member) {
        //返回对象
        return memberDAO.queryMemberByUsernameAndPassword
                (member.getUsername(), member.getPassword());
    }
}

LoginServlet 用于验证前端

package com.yinhai.furns.web;

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import com.yinhai.furns.javabean.Member;
import com.yinhai.furns.service.MemberService;
import com.yinhai.furns.service.impl.MemberServiceImpl;

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;

/**
 * @author 银小海
 * @version 1.0
 * @email yinhai14@qq.com
 */
@WebServlet(name = "LoginServlet",urlPatterns = "/loginServlet")
public class LoginServlet extends HttpServlet {
    private MemberService memberService = new MemberServiceImpl();
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("user-name");
        String password = request.getParameter("user-password");
        if (!memberService.isExistsUsername(username)){
            System.out.println("不存在 请重新登录");
            request.getRequestDispatcher("/views/member/login.html").forward(request,response);
            return;
        }
        if(memberService.login(new Member(null,username,password,null)) == null){
            System.out.println("密码错误 重新登录");
            request.getRequestDispatcher("/views/member/login.html").forward(request,response);
            return;
        }
        System.out.println("登录成功");
        request.getRequestDispatcher("/views/member/login_ok.jsp").forward(request,response);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}

六、实现功能05 - 登录错误提示 表单回显

在LoginServlet内添加回显以及消息提示

@WebServlet(name = "LoginServlet",urlPatterns = "/loginServlet")
public class LoginServlet extends HttpServlet {
    private MemberService memberService = new MemberServiceImpl();
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("user-name");
        String password = request.getParameter("user-password");
        if (!memberService.isExistsUsername(username)){
            System.out.println("用户名或者密码错误");
            request.setAttribute("msg","用户名或者密码错误");
            request.setAttribute("user-name",username);
            request.getRequestDispatcher("/views/member/login.jsp").forward(request,response);
            return;
        }
        if(memberService.login(new Member(null,username,password,null)) == null){
            System.out.println("密码错误 重新登录");
            request.setAttribute("msg","密码错误 重新登录");
            request.setAttribute("user-name",username);
            request.getRequestDispatcher("/views/member/login.jsp").forward(request,response);
            return;
        }
        System.out.println("登录成功");
        request.getRequestDispatcher("/views/member/login_ok.jsp").forward(request,response);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}

将前段页面改为jsp 并使用EL表达式

                        <div id="lg1" class="tab-pane active">
                            <div class="login-form-container">
                                <div class="login-register-form">
                                     <span style="float: right; font-weight: bold; font-size: 20pt; margin-left: 10px;">
                                         ${msg}
                                     </span>

 添加动态显示用户名

在对应的地方使用el表达式即可

七、实现功能06 - 合并servlet

1.使用if else解决

使用switch - case进行判断 

package com.yinhai.furns.web;

import com.yinhai.furns.javabean.Member;
import com.yinhai.furns.service.MemberService;
import com.yinhai.furns.service.impl.MemberServiceImpl;
import com.yinhai.furns.utils.JDBCUtilsByDruid;

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;

/**
 * @author 银小海
 * @version 1.0
 * @email yinhai14@qq.com
 */
@WebServlet(name = "MemberServlet", urlPatterns = "/memberServlet")
public class MemberServlet extends HttpServlet {
    private MemberService memberService = new MemberServiceImpl();

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("user-name");
        String password = request.getParameter("user-password");
        String email = request.getParameter("user-email");
        String action = request.getParameter("action");
        System.out.println(action);
        switch (action) {
            case "login":
                if (!memberService.isExistsUsername(username)) {
                    System.out.println("用户不存在");
                    request.setAttribute("msg", "用户不存在");
                    request.getRequestDispatcher("/views/member/login.jsp").forward(request, response);
                    return;
                }
                if (memberService.login(new Member(null, username, password, null)) == null) {
                    System.out.println("密码错误 重新登录");
                    request.setAttribute("msg", "密码错误 重新登录");
                    request.setAttribute("username", username);
                    request.getRequestDispatcher("/views/member/login.jsp").forward(request, response);
                    return;
                }
                System.out.println("登录成功");
                request.getRequestDispatcher("/views/member/login_ok.jsp").forward(request, response);
                break;
            case "register":
                if (!memberService.isExistsUsername(username)) {
                    System.out.println(username + "用户可用" + password + email);
                    Member member = new Member(null, username, password, email);
                    if (memberService.registerMember(member)) {
                        request.getRequestDispatcher("/views/member/register_ok.jsp").forward(request, response);
                        JDBCUtilsByDruid.commit();
                    } else {
                        request.getRequestDispatcher("/views/member/register_fail.jsp").forward(request, response);
                    }
                } else {
                    System.out.println("用户存在 无法注册");
                    request.setAttribute("msg", "用户存在 无法注册");
                    request.getRequestDispatcher("/views/member/login.jsp").forward(request, response);
                }
                break;
        }


    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

2.反射 +  模版设计 + 动态绑定

package com.yinhai.furns.web;

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.lang.reflect.Method;

/**
 * @author 银小海
 * @version 1.0
 * @email yinhai14@qq.com
 */
public abstract class BasicServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //解决接收到的数据中文乱码问题
        request.setCharacterEncoding("utf-8");

        //System.out.println("BasicServlet doPost()");
        //获取到action的值
        //老韩提示:如果我们使用了模板模式+反射+动态绑定,要满足action的value 和 方法名一致!!!
        String action = request.getParameter("action");
        //System.out.println("action=" + action);

        //使用反射,获取当前对象的方法
        //老韩解读
        //1.this 就是请求的Servlet
        //2.declaredMethod 方法对象就是当前请求的servlet对应的"action名字" 的方法, 该方法对象(declaredMethod)
        //  是变化的,根据用户请求
        //3.使用模板模式+反射+动态机制===> 简化多个 if--else if---..
        try {
            Method declaredMethod =
                    this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
            System.out.println("declaredMethod=" + declaredMethod);
            //使用方法对象,进行反射调用
            declaredMethod.invoke(this, request, response);

        } catch (Exception e) {
            //java基础->异常机制
            //将发生的异常,继续throw
            //老师心得体会: 异常机制是可以参与业务逻辑
            throw new RuntimeException(e);

        }

    }

}

然后子类servlet继承该Servlet 随后只写login以及register方法即可

package com.yinhai.furns.web;

import com.yinhai.furns.javabean.Member;
import com.yinhai.furns.service.MemberService;
import com.yinhai.furns.service.impl.MemberServiceImpl;
import com.yinhai.furns.utils.JDBCUtilsByDruid;

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;

/**
 * @author 银小海
 * @version 1.0
 * @email yinhai14@qq.com
 */
@WebServlet(name = "MemberServlet", urlPatterns = "/memberServlet")
public class MemberServlet extends BasicServlet {
    private MemberService memberService = new MemberServiceImpl();
    
    /**
     * 处理会员的注册
     *
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    protected void register(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("======MemberServlet register()========");
        //接收用户注册信息-> 一定要去看前端页面字段..
        //用户名
        String username = request.getParameter("user-name");
        String password = request.getParameter("user-password");
        String email = request.getParameter("user-email");
        //获取用户提交验证码
        String code = request.getParameter("code");
        //从session中获取到验证码
        // String token = (String) request.getSession().getAttribute(KAPTCHA_SESSION_KEY);
        //立即删除session验证码->防止该验证码被重复使用
        // request.getSession().removeAttribute(KAPTCHA_SESSION_KEY);
        //如果token为空,并且和用户提交的验证码一致,就继续
        // if (token != null && token.equalsIgnoreCase(code)) {
            //判断这个用户名是不是可用
            if (!memberService.isExistsUsername(username)) {
                //注册
                //System.out.println("用户名 " + username + " 不存在, 可以注册");
                //构建一个Member对象
                Member member = new Member(null, username, password, email);
                if (memberService.registerMember(member)) {
                    //请求转发
                    request.getRequestDispatcher("/views/member/register_ok.jsp")
                            .forward(request, response);
                } else {
                    //请求转发
                    request.getRequestDispatcher("/views/member/register_fail.jsp")
                            .forward(request, response);
                }

            } else {
                //返回注册页面
                //后面可以加入提示信息...
                request.getRequestDispatcher("/views/member/login.jsp")
                        .forward(request, response);
            }
        // } else { //验证码不正确
        //     request.setAttribute("msg", "验证码不正确~");
        //     //如果前端需要回显某些数据
        //     request.setAttribute("username", username);
        //     request.setAttribute("email", email);
        //     //带回一个信息 要显示到注册选项页
        //     request.setAttribute("active", "register");
        //     request.getRequestDispatcher("/views/member/login.jsp").forward(request, response);
        // }

    }

    /**
     * 处理会员登录
     *
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("======MemberServlet login()========");
        //System.out.println("LoginServlet 被调用..");
        //老韩说明:如果在登录页面, 用户没有输入内容,就直接提交,后台接收到的是""
        String username = request.getParameter("user-name");
        String password = request.getParameter("user-password");
        Member member = memberService.login(new Member(null, username, password, null));
        if (member == null) { //用户没有在DB
            //System.out.println(member + " 登录失败...");
            //把登录错误信息,放入到request域 => 如果忘了,可以看servlet / jsp
            request.setAttribute("msg", "用户名或者密码错误");
            request.setAttribute("username", username);
            //页面转发
            request.getRequestDispatcher("/views/member/login.jsp")
                    .forward(request, response);
        } else { //用户在DB
            //System.out.println(member + " 登录成功~...");

            //将得到member对象放入到session
            request.getSession().setAttribute("member", member);
            //老师做了一个简单处理
            if ("admin".equals(member.getUsername())) {
                request.getRequestDispatcher("/views/manage/manage_menu.jsp")
                        .forward(request, response);
            } else {
                request.getRequestDispatcher("/views/member/login_ok.jsp")
                        .forward(request, response);
            }
        }

    }
}

八、功能07 - 后台管理家具

创建furn表

package com.yinhai.furns.web;

import com.yinhai.furns.dao.BasicDAO;
import com.yinhai.furns.javabean.Furn;
import com.yinhai.furns.service.FurnService;
import com.yinhai.furns.service.impl.FurnServiceImpl;

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.util.List;

/**
 * @author 银小海
 * @version 1.0
 * @email yinhai14@qq.com
 */
@WebServlet(name = "FurnServlet",urlPatterns = "/manager/furnServlet")
public class FurnServlet extends BasicServlet {
    private FurnService furnService = new FurnServiceImpl();
    /**
     * 这里我们使用前面的模板设计模式+反射+动态绑定来的调用到list方法
     *
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    protected void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("FurnServlet list方法被调...");
        List<Furn> furns = furnService.queryFurns();
        //把furns集合放入到request域
        req.setAttribute("furns", furns);
        for (Furn furn : furns) {
            System.out.println(furn);
        }
        //请求转发
        req.getRequestDispatcher("/views/manage/furn_manage.jsp")
                .forward(req, resp);
    }
}

通过jstl标签取出并输出 

                            <c:forEach items="${requestScope.furns}" var="furn">
                                <tr>
                                    <td class="product-thumbnail">
                                        <a href="#"><img class="img-responsive ml-3" src="${furn.imgPath}"
                                                         alt=""/></a>
                                    </td>
                                    <td class="product-name"><a href="#">${furn.name}</a></td>
                                    <td class="product-name"><a href="#">${furn.maker}</a></td>
                                    <td class="product-price-cart"><span class="amount">${furn.price}</span></td>
                                    <td class="product-quantity">
                                            ${furn.sales}
                                    </td>
                                    <td class="product-quantity">
                                            ${furn.stock}
                                </tr>

编写admin的DAO

public class AdminDAOImpl extends BasicDAO implements AdminDAO {

    @Override
    public int saveAdmin(Admin admin) {
        String sql = "INSERT INTO `admin`(`username`,`password`) " +
                "VALUES(?,MD5(?))";
        return update(sql, admin.getUsername(),
                admin.getPassword());
    }

    @Override
    public Admin queryAdminByUsernameAndPassword(String username, String password) {
        String sql = "SELECT `id`,`username`,`password` FROM `admin` " +
                " WHERE `username`=? and `password`=md5(?)";
        return (Admin) querySingle(sql, Admin.class,username,password);
    }


}

编写对应的和前端交互的servlet

@WebServlet(name = "AdminServlet",urlPatterns = "/adminServlet")
public class AdminServlet extends BasicServlet {
    private AdminService adminService = new AdminServiceImpl();
    protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        Admin admin = new Admin(null, username, password);

        if(adminService.login(admin) == null){
            System.out.println("管理员不存在");
            request.getRequestDispatcher("/views/manage/manage_login.jsp").forward(request,response);
            return;
        }
        request.getRequestDispatcher("/views/manage/manage_menu.jsp").forward(request,response);

    }
}

九、功能08 - 后台管理 添加家具

@WebServlet(name = "FurnServlet",urlPatterns = "/manage/furnServlet")
public class FurnServlet extends BasicServlet {
    private FurnService furnService = new FurnServiceImpl();
    protected  void add(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        //获取家居信息
        String uname = request.getParameter("name");
        String maker = request.getParameter("maker");
        String price = request.getParameter("price");
        String sales = request.getParameter("sales");
        String stock = request.getParameter("stock");
        String defaultPath = "assets/images/product-image/default.jpg";
        Furn furn = new Furn(null, uname, maker, new BigDecimal(price), new Integer(sales), new Integer(stock), defaultPath);
        System.out.println(furn);
        furnService.addFurn(furn);
        request.getRequestDispatcher("/manage/furnServlet?action=list")
               .forward(request, response);
    }
public class FurnServiceImpl implements FurnService {
    private FurnDAO furnDAO = new FurnDAOImpl();
    //定义属性FurnDAO对象
    /**
     * 返回家居信息
     * @return
     */
    @Override
    public List<Furn> queryFurns() {
        return furnDAO.queryFurns();
    }

    @Override
    public int addFurn(Furn furn) {
        return furnDAO.addFurn(furn);
    }
}
public class FurnDAOImpl extends BasicDAO implements FurnDAO {
    @Override
    public int addFurn(Furn furn) {
        String sql = "INSERT INTO furn(`id`,`name`,maker,price,sales,stock,img_path)\n" +
                "\tVALUES(NULL,?,?,?,?,?,?)";
        return update(sql,furn.getName(),
                furn.getMaker(),furn.getPrice(),furn.getSales(),furn.getStock(),furn.getImgPath());
    }
}

细节 解决中文乱码问题 在BasicDAO上设置request response的文本格式

细节 解决表重复提交问题 使用重定向即可

细节 后端验证添加家具的合法性

 //我们可以对获取的到数据, 进行一个校验
        //1. 使用java的正则表达式来验证 sales是一个正整数
        //2. 如果没有通过校验,则直接返回furn_add.jsp -> request.setAttribute("mes","xx")
        //3. 这里可以直接进行转换
        //try {
        //    int i = Integer.parseInt(sales);
        //}catch (NumberFormatException e) {
        //    //System.out.println("转换异常...");
        //    req.setAttribute("mes", "销量数据格式不对...");
        //    //返回到furn_add.jsp
        //    req.getRequestDispatcher("/views/manage/furn_add.jsp")
        //            .forward(req, resp);
        //    return;
        //}

        //String stock = req.getParameter("stock");
        //图片的路径 imgPath 使用默认即可
        //Furn furn = null;
        //try {
        //    furn = new Furn(null, name, maker, new BigDecimal(price),
        //            new Integer(sales), new Integer(stock), "assets/images/product-image/default.jpg");
        //} catch (NumberFormatException e) {
        //    req.setAttribute("mes", "添加数据格式不对...");
        //    //返回到furn_add.jsp
        //    req.getRequestDispatcher("/views/manage/furn_add.jsp")
        //            .forward(req, resp);
        //    return;
        //}

        //后面我们会学习SpringMVC -> 专门的用于数据校验的规则/框架 JSR303... Hibernate Validator

细节 使用工具类DataUtils 完成自动封装JavaBean

1. BeanUtils工具类,它可以一次性的把所有请求的参数注入到JavaBean中。

2. BeanUtils工具类,经常用于把Map中的值注入到JavaBean中,或者是对象属性值的拷贝操作

3. BeanUtils不是Jdk的类,需要导入需要的jar包: commons-beanutils-1.8.0.jar

commons-logging-1.1.1.jar

//使用BeanUtils完成javabean对象的自动封装.
        //
        // Furn furn = new Furn();
        // try {
        //    //讲 req.getParameterMap() 数据封装到furn 对象
        //    //使用反射将数据封装, 有一个前提就是表单提交的数据字段名
        //    //<input name="maker" style="width: 90%" type="text" value=""/>
        //    //需要和封装的Javabean的属性名一致
        //    BeanUtils.populate(furn, request.getParameterMap());
        // } catch (Exception e) {
        //    e.printStackTrace();
        // }
        // 自动将提交的数据,封装到Furn对象
        Furn furn =
                DataUtils.copyParamToBean(request.getParameterMap(), new Furn());
        System.out.println(furn);
        furnService.addFurn(furn);
public class DataUtils {
    //将方法,封装到静态方法,方便使用
    public static <T> T copyParamToBean(Map value, T bean) {
        try {
            BeanUtils.populate(bean, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bean;
    }

}

在构造javabean的时候在Furn内赋予一个默认值 给这个类自动装入

十、功能09 后台管理 删除家具

前端对x图标进行绑定事件 弹出是否删除该名字的家具

Servlet增加功能

@WebServlet(name = "FurnServlet",urlPatterns = "/manage/furnServlet")
public class FurnServlet extends BasicServlet {
protected void del(HttpServletRequest request,HttpServletResponse response){
        int id = DataUtils.parseInt(request.getParameter("id"), 0);
        System.out.println(furnService.deleteFurnById(id));
    }
}

Service增加功能

    public int deleteFurnById(int id) {
        return furnDAO.deleteFurnById(id);
    }

DAO类增加功能 

public class FurnDAOImpl extends BasicDAO implements FurnDAO {
    public int deleteFurnById(int id) {
        String sql = "DELETE FROM furn WHERE id = ?";
        return update(sql,id);
    }
}

十一、功能实现 10 后台管理 修改家具

查询对应的id的家具

protected void showFurn(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        int id = DataUtils.parseInt(request.getParameter("id"),0);
        Furn furn = furnService.queryFurnById(id);
        System.out.println(furn);
        request.setAttribute("furn",furn);
        //请求转发
        request.getRequestDispatcher("/views/manage/furn_update.jsp").forward(request,response);
    }

以上完成回显操作 下一步做修改的操作

  @Override
    public int updateFurn(Furn furn) {
        String sql = "UPDATE furn SET `name` = ? , `maker` = ? , `price` = ? , sales = ?" +
                " , stock = ? , `img_path` = ?" +
                " WHERE id = ?";
        return update(sql,furn.getName(),furn.getMaker(),
                furn.getPrice(),furn.getSales(),furn.getStock(),furn.getImgPath(),furn.getId());
    }

前端页面也调整 使用jstl标签拿出

十二、功能实现11 分页显示

将分页作为一个Bean模型 

package com.yinhai.furns.javabean;

import java.util.List;

/**
 * @author 银小海
 * @version 1.0
 * @email yinhai14@qq.com
 * 一个分页的数据模型 包含了分页的各种信息
 */
//用一个泛型 分页模型对应的数据类型是不确定的
public class Page<T> {
    //每页显示多少条记录可以在其他地方也用到 建议置为常量
    //ctrl + shift + u 切换大小写
    public static final Integer PAGE_SIZE = 3;

    //表示显示当前页
    private  Integer pageNo;

    //每页显示多少记录
    private  Integer pageSize = PAGE_SIZE;

    //表示共有多少页
    private Integer pageTotalCount;

    //表示的是共有多少条记录 通过totalRow和pageSize计算得到pageTotalCount
    private Integer totalRow;

    //表示当前页要显示的数据
    private List<T> items;

    //分页导航的字符串
    private String url;

    public Integer getPageNo() {
        return pageNo;
    }

    public void setPageNo(Integer pageNo) {
        this.pageNo = pageNo;
    }

    public Integer getPageSize() {
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }

    public Integer getPageTotalCount() {
        return pageTotalCount;
    }

    public void setPageTotalCount(Integer pageTotalCount) {
        this.pageTotalCount = pageTotalCount;
    }

    public Integer getTotalRow() {
        return totalRow;
    }

    public void setTotalRow(Integer totalRow) {
        this.totalRow = totalRow;
    }

    public List<T> getItems() {
        return items;
    }

    public void setItems(List<T> items) {
        this.items = items;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

分析 page的那些属性可以从数据库获取 就把对应的属性交给DAO赋值

@Override
    public int getTotalRow() {
        String sql = "SELECT COUNT(*) FROM furn";
        // return (int) queryScalar(sql); => 会报转换异常
        return ((Number) queryScalar(sql)).intValue();
    }

    @Override
    public List<Furn> getPageItems(int begin, int pageSize) {
        String sql = "SELECT `id`,`name`,maker,price,sales,stock,img_path imgPath\n" +
                " FROM furn ";
        return null;
    }

其他的交给Service处理

public class FurnServiceImpl implements FurnService {
    @Override
    public Page<Furn> page(int pageNo, int pageSize) {
        Page<Furn> page = new Page<>();
        page.setPageNo(pageNo);
        page.setPageSize(pageSize);
        int totalRow = furnDAO.getTotalRow();
        page.setTotalRow(totalRow);
        //pageTotalCount最大页数 需要通过算法计算得到
        int pageTotalCount = totalRow / pageSize;
        if(totalRow % pageSize > 0){
            pageTotalCount += 1;
        }
        page.setPageTotalCount(pageTotalCount);
        //private List<T> items
        //计算begin
        //private List<T> items
        //老师开始计算begin-> 小小算法
        //验证: pageNo = 1 pageSize = 3 => begin =0
        //验证: pageNo = 3 pageSize = 2 => begin =4
        //OK => 但是注意这里隐藏一个坑, 现在你看不到, 后面会暴露
        int begin = (pageNo - 1) * pageSize;
        List<Furn> pageItems = furnDAO.getPageItems(begin, pageSize);
        page.setItems(pageItems);
        //还差一个url => 分页导航,先放一放
        return page;
    }
}

Servlet调用 

protected void page(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        int pageNo = DataUtils.parseInt(req.getParameter("pageNo"), 1);
        int pageSize = DataUtils.parseInt(req.getParameter("pageSize"), Page.PAGE_SIZE);

        //调用service方法, 获取Page对象
        Page<Furn> page = furnService.page(pageNo, pageSize);
        //将page放入到request域
        req.setAttribute("page", page);
        //请求转发到furn_manage.jsp
        req.getRequestDispatcher("/views/manage/furn_manage.jsp")
                .forward(req, resp);
    }

 

十三、功能实现 12 - 分页导航

<!--  Pagination Area Start 分页导航条 -->
        <div class="pro-pagination-style text-center mb-md-30px mb-lm-30px mt-6" data-aos="fade-up">
            <ul>
                <%--如果当前页 > 1 , 就显示上一页--%>
                <c:if test="${requestScope.page.pageNo > 1}">
                    <li><a href="manage/furnServlet?action=page&pageNo=${requestScope.page.pageNo - 1}">上一页</a></li>
                </c:if>
                <%--<li><a class="active" href="#">3</a></li>--%>
                <%--<li><a href="#">4</a></li>--%>
                <%--<li><a href="#">5</a></li>--%>
                <%--    显示所有的分页数, 先容易,再困难
                    老师思路: 先确定开始页数 begin 第1页
                            再确定结束页数 end 第pageTotalCount页
                    学生困惑:如果页数很多,怎么办? => 算法最多显示5页[这个规则可以由程序员决定.]
                            希望,小伙伴自己先想一想...=> 后面

                    老师分析
                    1. 如果总页数<=5, 就全部显示
                    2. 如果总页数>5, 按照如下规则显示(这个规则是程序员/业务来确定):
                    2.1 如果当前页是前3页, 就显示1-5
                    2.2 如果当前页是后3页, 就显示最后5页
                    2.3 如果当前页是中间页, 就显示 当前页前2页, 当前页 , 当前页后两页

                    这里的关键就是要根据不同的情况来初始化begin, end
                --%>
                <c:choose>
                    <%--如果总页数<=5, 就全部显示--%>
                    <c:when test="${requestScope.page.pageTotalCount <=5 }">
                        <c:set var="begin" value="1"/>
                        <c:set var="end" value="${requestScope.page.pageTotalCount}"/>
                    </c:when>
                    <%--如果总页数>5--%>
                    <c:when test="${requestScope.page.pageTotalCount > 5}">
                        <c:choose>
                            <%--如果当前页是前3页, 就显示1-5--%>
                            <c:when test="${requestScope.page.pageNo <= 3}">
                                <c:set var="begin" value="1"/>
                                <c:set var="end" value="5"/>
                            </c:when>
                            <%--如果当前页是后3页, 就显示最后5页--%>
                            <c:when test="${requestScope.page.pageNo > requestScope.page.pageTotalCount - 3}">
                                <c:set var="begin" value="${requestScope.page.pageTotalCount - 4}"/>
                                <c:set var="end" value="${requestScope.page.pageTotalCount}"/>
                            </c:when>
                            <%--如果当前页是中间页, 就显示 当前页前2页, 当前页 , 当前页后两页--%>
                            <c:otherwise>
                                <c:set var="begin" value="${requestScope.page.pageNo - 2}"/>
                                <c:set var="end" value="${requestScope.page.pageNo + 2}"/>
                            </c:otherwise>
                        </c:choose>
                    </c:when>
                </c:choose>

                <c:forEach begin="${begin}" end="${end}" var="i">
                    <%--如果i是当前页, 就使用class="active" 修饰--%>
                    <c:if test="${i == requestScope.page.pageNo}">
                        <li><a class="active" href="manage/furnServlet?action=page&pageNo=${i}">${i}</a></li>
                    </c:if>
                    <c:if test="${i != requestScope.page.pageNo}">
                        <li><a href="manage/furnServlet?action=page&pageNo=${i}">${i}</a></li>
                    </c:if>
                </c:forEach>

                <%--如果当前页 < 总页数 , 就显示下一页--%>
                <c:if test="${requestScope.page.pageNo < requestScope.page.pageTotalCount}">
                    <li><a href="manage/furnServlet?action=page&pageNo=${requestScope.page.pageNo + 1}">下一页</a></li>
                </c:if>
                <li><a href="#">共 ${requestScope.page.pageTotalCount} 页</a></li>
            </ul>
        </div>
        <!--  Pagination Area End -->

进行修改 删除 添加 家具之后 能够回显到原来操作所在的页面

修改一步步转发 到最后重定向到page页面

这几个都这么做都在修改请求转发地址上完成

@WebServlet(name = "FurnServlet", urlPatterns = "/manage/furnServlet")
public class FurnServlet extends BasicServlet {
    protected void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取家居信息
        // String uname = request.getParameter("name");
        // String maker = request.getParameter("maker");
        // String price = request.getParameter("price");
        // String sales = request.getParameter("sales");
        //
        //
        // String stock = request.getParameter("stock");
        // String defaultPath = "assets/images/product-image/default.jpg";
        // Furn furn = new Furn(null, uname, maker, new BigDecimal(price), new Integer(sales), new Integer(stock), defaultPath);
        //我们可以对获取的到数据, 进行一个校验
        //1. 使用java的正则表达式来验证 sales是一个正整数
        //2. 如果没有通过校验,则直接返回furn_add.jsp -> request.setAttribute("mes","xx")
        //3. 这里可以直接进行转换
        //try {
        //    int i = Integer.parseInt(sales);
        //}catch (NumberFormatException e) {
        //    //System.out.println("转换异常...");
        //    req.setAttribute("mes", "销量数据格式不对...");
        //    //返回到furn_add.jsp
        //    req.getRequestDispatcher("/views/manage/furn_add.jsp")
        //            .forward(req, resp);
        //    return;
        //}

        //String stock = req.getParameter("stock");
        //图片的路径 imgPath 使用默认即可
        //Furn furn = null;
        //try {
        //    furn = new Furn(null, name, maker, new BigDecimal(price),
        //            new Integer(sales), new Integer(stock), "assets/images/product-image/default.jpg");
        //} catch (NumberFormatException e) {
        //    req.setAttribute("mes", "添加数据格式不对...");
        //    //返回到furn_add.jsp
        //    req.getRequestDispatcher("/views/manage/furn_add.jsp")
        //            .forward(req, resp);
        //    return;
        //}

        //后面我们会学习SpringMVC -> 专门的用于数据校验的规则/框架 JSR303... Hibernate Validator
        //这里我们使用第二种方式, 完成将前端提交的数据, 封装成Furn的Javabean对象
        //使用BeanUtils完成javabean对象的自动封装.
        //
        // Furn furn = new Furn();
        // try {
        //    //讲 req.getParameterMap() 数据封装到furn 对象
        //    //使用反射将数据封装, 有一个前提就是表单提交的数据字段名
        //    //<input name="maker" style="width: 90%" type="text" value=""/>
        //    //需要和封装的Javabean的属性名一致
        //    BeanUtils.populate(furn, request.getParameterMap());
        // } catch (Exception e) {
        //    e.printStackTrace();
        // }
        // 自动将提交的数据,封装到Furn对象
        Furn furn =
                DataUtils.copyParamToBean(request.getParameterMap(), new Furn());
        System.out.println(furn);
        furnService.addFurn(furn);

        //老师说明: 因为这里使用请求转发, 当用户刷新页面时, 会重新发出一次添加请求
        // request.getRequestDispatcher("/manage/furnServlet?action=list")
        //        .forward(request, response);
        //就会造成数据重复提交: 解决方案使用 重定向即可.
        //因为重定向实际是让浏览器重新发请求, 所以我们回送的url , 是一个完整url
        // response.sendRedirect(request.getContextPath() + "/manage/furnServlet?action=list");
        //以分页的方式显示
        response.sendRedirect(request.getContextPath()
                + "/manage/furnServlet?action=page&pageNo=" + request.getParameter("pageNo"));
    }

    protected void del(HttpServletRequest request, HttpServletResponse response) throws IOException {
        int id = DataUtils.parseInt(request.getParameter("id"), 0);
        System.out.println(furnService.deleteFurnById(id));

        response.sendRedirect(request.getContextPath()
                + "/manage/furnServlet?action=page&pageNo=" + request.getParameter("pageNo"));
    }

    protected void showFurn(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        int id = DataUtils.parseInt(request.getParameter("id"), 0);
        Furn furn = furnService.queryFurnById(id);
        System.out.println(furn);
        request.setAttribute("furn", furn);
        //再把获取到的showPage再传回去
        // request.setAttribute("pageNo",request.getParameter("pageNo"));
        // 如果是在同一个作用域request内的请求是不需要再转发的 在下个页面可以用param.pageNo获取
        //请求转发
        request.getRequestDispatcher("/views/manage/furn_update.jsp").forward(request, response);
    }

    protected void update(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Furn furn = DataUtils.copyParamToBean(request.getParameterMap(), new Furn());
        System.out.println("update" + furn);
        System.out.println(furnService.updateFurn(furn));
        //请求重定向
        // response.sendRedirect(request.getContextPath() + "/manage/furnServlet?action=list");
        //这里考虑分页转发
        System.out.println(request.getContextPath()
                + "/manage/furnServlet?action=page&pageNo=" + request.getParameter("pageNo"));
        response.sendRedirect(request.getContextPath()
                + "/manage/furnServlet?action=page&pageNo=" + request.getParameter("pageNo"));
    }
    protected void page(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        int pageNo = DataUtils.parseInt(req.getParameter("pageNo"), 1);
        int pageSize = DataUtils.parseInt(req.getParameter("pageSize"), Page.PAGE_SIZE);

        //调用service方法, 获取Page对象
        Page<Furn> page = furnService.page(pageNo, pageSize);
        if(page.getItems().size() == 0){
            page = furnService.page(page.getPageTotalCount(), pageSize);
        }
        //将page放入到request域
        req.setAttribute("page", page);
        //请求转发到furn_manage.jsp
        req.getRequestDispatcher("/views/manage/furn_manage.jsp")
                .forward(req, resp);
    }


}

十四、功能实现13 - 首页分页

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1375707.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

imgaug库指南(17):从入门到精通的【图像增强】之旅

引言 在深度学习和计算机视觉的世界里&#xff0c;数据是模型训练的基石&#xff0c;其质量与数量直接影响着模型的性能。然而&#xff0c;获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此&#xff0c;数据增强技术应运而生&#xff0c;成为了解决这一问题的…

Win2008R2上RedisDesktopManager 黑屏

问题&#xff1a; 运行发现右侧显示缓存信息的部分是黑屏。 解决方式&#xff1a; 管理工具->远程桌面服务->远程桌面会话主机配置->RDP-TCP->属性->客户端设置->颜色深度->限制最大颜色深度,将16位改为32位

基于嵌入式的智能台灯系统

基于嵌入式的智能台灯系统 功能说明 通过微信小程序控制台灯的亮灭及亮度。采集温湿度传到微信小程序上&#xff0c;台灯可以显示实时北京时间。 功能展示 01智能台灯演示 Mqtt服务器 http://www.yoyolife.fun/iot&#xff1a;Mqtt服务器&#xff0c;我是在这里注册的&#x…

【机器学习】半监督学习

一、问题假设 要利用无标签样本进行训练&#xff0c;必须对样本的分布进行假设&#xff1f; 二、启发式算法 自训练和协同训练是两种常用的半监督学习的方法&#xff0c;它们的主要区别在于使用的模型的数量和类型。 自训练&#xff1a;自训练是一种使用单个模型的半监督学习的…

【EI会议征稿通知】2024年机器学习与智能计算国际学术会议(MLIC 2024)

2024年机器学习与智能计算国际学术会议&#xff08;MLIC 2024&#xff09; 2024 International Conference on Machine learning and intelligent computing 智能计算与机器学习被广泛应用于大数据分析、人工智能、智能制造、智能交通、智能电网、智慧城市、智慧医疗、金融科…

语境化语言表示模型-ELMO、BERT、GPT、XLnet

一.语境化语言表示模型介绍 语境化语言表示模型&#xff08;Contextualized Language Representation Models&#xff09;是一类在自然语言处理领域中取得显著成功的模型&#xff0c;其主要特点是能够根据上下文动态地学习词汇和短语的表示。这些模型利用了上下文信息&#xf…

人工智能行业的发展前景如何?

人工智能&#xff08;AI&#xff09;已经成为如今科技领域的热门话题之一&#xff0c;从图像识别到自动驾驶&#xff0c;从语音助手到智能机器人&#xff0c;AI技术正在改变我们的生活方式。随着技术的不断发展和应用的扩大&#xff0c;人工智能行业的发展前景无疑是非常广阔的…

ios 1x/2x/3x

asset文件下可以配置1x/2x/3x图&#xff0c;然后不同机型屏幕会根据[UIScreen mainScreen].scale,自动按需读取相关图片,imageView可以根据image自动适应,需求有个包体积优化&#xff0c;使用 3x图webp格式替换asset图片&#xff0c;由于代码没有根据image尺寸自适应没有进行si…

构建基于RHEL9系列(CentOS9,AlmaLinux9,RockyLinux9等)的Nginx1.24.0的RPM包

本文适用&#xff1a;rhel9系列&#xff0c;或同类系统(CentOS9,AlmaLinux9,RockyLinux9等) 文档形成时期&#xff1a;2023年 因系统版本不同&#xff0c;构建部署应略有差异&#xff0c;但本文未做细分&#xff0c;对稍有经验者应不存在明显障碍。 因软件世界之复杂和个人能力…

【JVM】初识 Jvm

目录 什么是JVM JVM 的功能 常见的JVM 什么是JVM JVM 的全程是 Java Virtual Machine ( java 虚拟机 &#xff09; JVM 是一种用于计算设备的规范&#xff0c;也是一个虚构出来的计算机&#xff0c;通过在实际的计算机上仿真模拟各种计算机功能实现&#xff0c;JVM 屏蔽了…

函数——自制函数(c++)

今天进入自制函数。 自制函数&#xff0c;需要自己定义其功能。比如&#xff0c;设置一个没有参数没有返回值的积木&#xff0c;叫“aaa”。那么&#xff0c;如果想要运行“aaa”&#xff0c;就需要以下代码&#xff1a; void aaa(); 告诉系统有“aaa”…

如何从多个文件夹里各提取相应数量的文件放一起到新文件夹中形成多文件夹组合

首先&#xff0c;需要用到的这个工具&#xff1a; 百度 密码&#xff1a;qwu2蓝奏云 密码&#xff1a;2r1z 说明一下情况 文件夹&#xff1a;1、2、3里面分别放置了各100张动物的图片&#xff0c;模拟实际情况的各种文件 操作&#xff1a;这里演示的是从3个文件夹里各取2张图…

恒创科技:解决Windows服务器磁盘空间不足的问题

​  服务器硬盘的大小是决定空间是否充足的主要因素。但在日常使用中&#xff0c;服务器和网站备份会消耗大量存储空间&#xff0c;如果维护不当&#xff0c;最终将耗尽您的容量。同样&#xff0c;日志文件、临时文件和数据库可以在硬盘驱动器上或回收站中无休止地建立。当您…

MidTool的GPT-4:开启智能语言新纪元

MidTool平台上的GPT-4是由OpenAI开发的最新一代语言预测模型。与前一代GPT-3相比&#xff0c;GPT-4在理解深度、文本生成的连贯性和创造性方面都有了显著的提升。这意味着用户可以期待更加自然、更加精准的交流体验&#xff0c;以及更高质量的内容创作。 1. 无缝对话体验 在M…

高效构建Java应用:Maven入门和进阶(四)

高效构建Java应用&#xff1a;Maven入门和进阶&#xff08;四&#xff09; 四. Maven聚合和继承特性4.1 Maven工程继承关系4.2 Maven工程聚合关系 四. Maven聚合和继承特性 4.1 Maven工程继承关系 继承概念 Maven 继承是指在 Maven 的项目中&#xff0c;让一个项目从另一个项目…

使用 Docker 部署 Halo 博客系统

:::info 项目地址&#xff1a;https://github.com/halo-dev/halo ::: 一、Halo 介绍 1&#xff09;Halo 简介 Halo 是一款强大易用的开源建站工具&#xff0c;它让你无需太多的技术知识就可以快速搭建一个博客、网站或者内容管理系统。具备可插拔架构、主题套用、富文本编辑器…

05-微服务Sentinel流量哨兵

一、Sentinel介绍 1.1 什么是Sentinel 分布式系统的流量防卫兵&#xff1a;随着微服务的普及&#xff0c;服务调用的稳定性变得越来越重要。Sentinel以“流量”为切入点&#xff0c;在流量控制、断路、负载保护等多个领域开展工作&#xff0c;保障服务可靠性。特点&#xff1…

MyBatis实战指南(二):工作原理与基础使用详解

MyBatis是一个优秀的持久层框架&#xff0c;它支持定制化SQL、存储过程以及高级映射。那么&#xff0c;它是如何工作的呢&#xff1f;又如何进行基础的使用呢&#xff1f;本文将带你了解MyBatis的工作原理及基础使用。 一、MyBatis的工作原理 1.1 MyBatis的工作原理 工作原理…

Vue基础-搭建Vue运行环境

这篇文章介绍了在Vue.js项目中进行开发环境搭建的关键步骤。包括node.js安装和配置、安装Vue及Vue CLI工具、安装webpack模板、安装vue-router、创建Vue项目等步骤。这篇文章为读者提供了清晰的指南&#xff0c;帮助他们快速搭建Vue.js开发环境&#xff0c;为后续的项目开发奠定…

小汪,TCP连接和断连夺命6连问你可能扛得住?

目录 TCP三次握手连接和四次挥手断连的几处疑问 一、建立连接&#xff0c;为什么是三次握手&#xff0c;而不是二次握手&#xff1f; 二、为什么每次建立 TCP 连接时&#xff0c;初始化的序列号都要求不一样呢&#xff1f; 三、断开连接&#xff0c;为什么是四次握手&#x…