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

一、项目开发流程

程序框架图

项目具体分层方案

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, 这里存放一个Connectionprivate 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没有连接//就从数据库连接池中,取出一个连接放入, threadLocalConntry {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 {//小伙伴要自己分析,需要哪些方法//提供一个通过用户名返回对应的Memberpublic 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*/@Overridepublic Member queryMemberByUsername(String username) {//老师提示,sql 先在sqlyog 测试,然后再拿到程序中//这里可以提高我们的开发效率,减少不必要的bugString sql = "SELECT `id`,`username`,`password`,`email` FROM `member`\n" +"WHERE `username` = ?";return querySingle(sql, Member.class, username);}/*** 保存一个会员** @param member 传入Member对象* @return 返回-1 就是失败,返回其它的数字就是受影响的行数*/@Overridepublic int saveMember(Member member) {String sql = "INSERT INTO `member`(`username`,`password`,`email`) " +" VALUES(?,MD5(?), ?)";return update(sql, member.getUsername(),member.getPassword(), member.getEmail());}@Overridepublic 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("用户不存在");}}@Testpublic 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 {@Overridepublic 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 {@Overridepublic 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 / jsprequest.setAttribute("msg", "用户名或者密码错误");request.setAttribute("username", username);//页面转发request.getRequestDispatcher("/views/member/login.jsp").forward(request, response);} else { //用户在DB//System.out.println(member + " 登录成功~...");//将得到member对象放入到sessionrequest.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 {@Overridepublic int saveAdmin(Admin admin) {String sql = "INSERT INTO `admin`(`username`,`password`) " +"VALUES(?,MD5(?))";return update(sql, admin.getUsername(),admin.getPassword());}@Overridepublic 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*/@Overridepublic List<Furn> queryFurns() {return furnDAO.queryFurns();}@Overridepublic int addFurn(Furn furn) {return furnDAO.addFurn(furn);}
}
public class FurnDAOImpl extends BasicDAO implements FurnDAO {@Overridepublic 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);}

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

  @Overridepublic 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计算得到pageTotalCountprivate 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赋值

@Overridepublic int getTotalRow() {String sql = "SELECT COUNT(*) FROM furn";// return (int) queryScalar(sql); => 会报转换异常return ((Number) queryScalar(sql)).intValue();}@Overridepublic 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 {@Overridepublic 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.jspreq.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-52.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.jspreq.getRequestDispatcher("/views/manage/furn_manage.jsp").forward(req, resp);}}

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

张驰咨询:集成产品开发(IPD)的原理和实践技巧

IPD&#xff0c;是集成产品开发&#xff08;Integrated Product Development&#xff09;的缩写&#xff0c;它是集成了众多管理模型和理论、众多企业最佳管理实践的一整套体系&#xff0c;可以帮助企业快速响应市场变化、缩短产品上市时间、减少资源浪费、提高生产力&#xff…

RK3399平台入门到精通系列讲解(基础篇)__LITTLE_ENDIAN_BITFIELD 宏的使用

🚀返回总目录 文章目录 一、什么是字节序二、小端模式(Little-Endian)三、大端模式(Big-Endian)四、__LITTLE_ENDIAN_BITFIELD 使用案例一、什么是字节序 在计算机中,数据是以最原始的二进制 0 和 1 的方式被存储的。在大多数现代计算机体系架构中,计算机的最小可寻址数…

【MATLAB源码-第107期】基于matlab的OFDM系统在瑞利信道下功率分配仿真,使用注水算法。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 在瑞利衰落信道下&#xff0c;OFDM&#xff08;正交频分复用&#xff09;系统的功率分配可以通过“注水算法”&#xff08;water-filling algorithm&#xff09;的方法来优化。这种算法的目的是在不同的子载波上分配不同的功…

Hive数据库:嵌入、本地、远程全攻略(上)

Hive分布式数据仓库工具 关系型数据库 建立在关系模型之上的数据库称为关系型数据库(关系模型是由埃德加科德于1970年提出的)&#xff0c;关系型数据库借助集合代数等数学概念处理数据库中的数据。数据查询语言SOL是基于关系型数据库的语言,能够对关系型数据库中的数据进行检…

CSS3中transform2D变形详解

CSS3变形 在CSS3中&#xff0c;动画效果包括3个部分&#xff1a; 变形(transform)过渡(transition)动画(animation) 在实际开发中&#xff0c;有时需要实现元素的各种变形效果&#xff0c;如平移&#xff0c;缩放&#xff0c;旋转&#xff0c;倾斜等。 在CSS3中&#xff0c…

Kafka的简介及架构

目录 消息队列 产生背景 消息队列介绍 常见的消息队列产品 应用场景 消息队列的消息模型 Kafka的基本介绍 简介 Kafka的架构 Kafka的使用 Kafka的shell命令 Kafka的Python API的操作 完成生产者代码 完成消费者代码 消息队列 产生背景 消息队列:指数据在一个容器…

PyCharm使用手册

配置文件和代码模板 文件注释模板&#xff1a; 注释项描述示例Project项目名称hello_pythonFile文件名称hello_python.pyAuthor作者Zhang SanDate创建时间2024-01-11 17:05:00PyVersionPython解释器版本Python3.7Description文件描述这是一个python语言入门文件 效果示例&am…

【阅读笔记】Chain of LoRA

一、论文信息 1 论文标题 Chain of LoRA: Efficient Fine-tuning of Language Models via Residual Learning 2 发表刊物 arXiv2023 3 作者团队 Department of Computer Science, Princeton University School of Computer Science and Engineering, Nanyang Technologic…

2023年人工智能的最新发展(下)

目录 1.MidJourney&#xff1a; 2.GAN: 3.Diffusion Model 4.DALLE、Disco Diffusion 5.Stable Diffusion 1.MidJourney&#xff1a; 2023年3月&#xff0c;一组中国小情侣的照片在网络上迅速走红。这组照片看起来普通&#xff0c;就像一对小情侣的合影&#xff0c;但实…

Go后端开发 -- 条件、循环语句 defer语句

Go后端开发 – 条件、循环语句 && defer语句 文章目录 Go后端开发 -- 条件、循环语句 && defer语句一、条件语句1.if ... else 语句2.switch语句3.select语句 二、循环语句1.for循环 三、defer语句1.defer语句的作用2.defer和return的先后顺序3.recover错误拦截…

212. 单词搜索 II(字典树的另一种类型)

大致思路是&#xff1a; 根据words列表建立字典树&#xff0c;其中注意在单词末尾&#xff0c;将原来的isEnd变量换成存储这个单词的变量&#xff0c;方便存储到ans中&#xff0c;另外&#xff0c;字典树的字节点由原来的Trie数组变为hashmap&#xff0c;方便检索字母。 建立…

C++ n皇后问题 || 深度优先搜索模版题

n− 皇后问题是指将 n 个皇后放在 nn 的国际象棋棋盘上&#xff0c;使得皇后不能相互攻击到&#xff0c;即任意两个皇后都不能处于同一行、同一列或同一斜线上。 现在给定整数 n &#xff0c;请你输出所有的满足条件的棋子摆法。 输入格式 共一行&#xff0c;包含整数 n 。 …