登录注册文件增删查改实现
需求:实现登录功能,注册功能。登录后文件可以进行增加删除修改查看等基本功能的操作。
知识点:mybatis ,Tomcat,servlet , asion , json ,req , resp ,session
前提准备:
pom.xml坐标导入:
导入Mybatis和Mysql驱动坐标,日志坐标,Servlet坐标
<dependencies> <!--mybatis环境--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency> <!--mysql环境--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--分页插件坐标--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.2</version> </dependency> <!--servlet环境--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!--jstl--> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency> <!--其他组件--> <!--junit单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--日志--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.20</version> </dependency> <!-- 添加logback-classic依赖 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <!-- 添加logback-core依赖 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> </dependencies> <build> <plugins> <!-- tomcat 插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>80</port> <path>/</path> <uriEncoding>utf-8</uriEncoding> </configuration> </plugin> </plugins> </build>
讯享网
mybatis需要的相关准备
- 创建的是mavenweb项目,且导入mybatis框架。需要在resources资源包下导入mybatis核心配置文件。写数据库连接和资源配置文件路径等。
- 在java项目下创建pojo包,里面写数据库中表对应的实体类,settergetter,toString,空参,满参构造。
- 在java项目下创建mapper包,里面写实体类对应的mapper接口。eg:实体类User mapper下就创建UserMapper接口,一个实体类对应一个mapper
- 在resources资源包下创建和mapper对应路径的mapper文件名.xml。详细SQL写这里,或者java中mappe的方法上写注解。
包名解析
pojo : 存放实体类
util:存放工具类
mapper : 存放操作数据库数据的类,
service : 存放业务处理的逻辑业务类,逻辑层
web : 存放与前端交互的类,界面层
登录
思路分析:
- 用户在登录页面输入用户名和密码,提交请求给LoginServlet
- 在LoginServlet中接收请求和数据[用户名和密码]
- 在LoginServlt中通过Mybatis实现调用UserMapper来根据用户名和密码查询数据库表
- 将查询的结果封装到User对象中进行返回
- 在LoginServlet中判断返回的User对象是否为null
- 如果为null,说明根据用户名和密码没有查询到用户,则登录失败,请求转发到登录页面,携带数据(用户名或者密码不正确,请重新登录)
- 如果不为null,则说明用户存在并且密码正确,则登录成功,请求转发到查询所有页面
代码实现:
数据处理mapper
写根据用户名和密码查询数据,返回一个user对象。给逻辑层查询使用
讯享网public interface UserMapper {
//查询是否有这个用户名密码 @Select("select * from tb_user where username=#{username} and password=#{password}") User selectNP(User user); }
细节解析:这个接口中查询用户名和密码是否存在,是一个简单SQL查询。可以直接使用注解。
查出来就是一条数据,没有数据就返回null
逻辑层
接收界面层传入数据,写一个对应的用户登录验证方法。类:UserService
public class UserService {
// 获取数据库连接方式。使用了工具类 private SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory(); // 判断登录的方法 public User selectDL(User user) {
//1. 获取SqlSession对象,用它来执行sql SqlSession sqlSession = sqlSessionFactory.openSession(); // 2,调用登录对比查询方法 UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user1 = mapper.selectNP(user); // 3, 返回数据 return user1; } }
细节分析:
- 这个类里面可以写关于user的所有逻辑处理,现在写的是登录判断selectDL方法
- 因为这个类需要连获取数据库连接,会写好多方法,所以直接写到类里面,所有方法可用。 private私有化其他类不可以用。
讯享网private SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
- 方法内调用mapper中写的SQL语句,返回数据即可。
界面层:
接收请求和数据,判断是否登录成功,响应数据
// 登录 @WebServlet("/loginServlet") public class LoginServlet extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 处理请求数据中文乱码 request.setCharacterEncoding("utf-8"); //1.接收用户数据 String username = request.getParameter("username"); String password = request.getParameter("password"); //2.封装用户对象 User user = new User(); user.setUsername(username); user.setPassword(password); //3.调用逻辑层进行判断 UserService userService = new UserService(); User user1 = userService.selectDL(user); //4. 判断用户对象是否为null // 响应数据中文乱码处理 response.setContentType("text/html;charset=utf-8"); if( user1 == null){
// 用户名信息错误,返回提示信息和登录页面 request.setAttribute("login_msg","用户名或密码错误"); // 跳转到login.jsp,请求转发页面上路径不变,不走网络,直接要跳转到位置即可 request.getRequestDispatcher("/login.jsp").forward(request,response); }else {
//用户登录成功,显示用户信息和进入里面.携带用户信息 // 用户信息存入session中,方便后期过滤登录和页面使用用户信息 HttpSession session = request.getSession(); session.setAttribute("user",user); request.getRequestDispatcher("/brand.html").forward(request,response); } } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response); } }
细节回顾:
- 前端传来的用户名和密码里面可能会包含中文,接收数据前需要处理中文乱码。乱码数据不能正确和数据库进行比对。
讯享网request.setCharacterEncoding("utf-8");
- 在响应时,有中文字符,也需要处理响应中文乱码
// 响应数据中文乱码处理 response.setContentType("text/html;charset=utf-8");
- 判断用户名密码正确要进入页面时,需要用session保存下用户信息,
(1) : 页面里面需要展示用户信息
(2) : 后期优化过滤登录时做登录判断
讯享网// 用户信息存入session中,方便后期过滤登录和页面使用用户信息 HttpSession session = request.getSession(); session.setAttribute("user",user);
注册
思路分析:
- 验证码判断,验证码错误,直接返回注册页面,不判断用户信息
- 验证码通过,判断用户名是否存在,存在:提示用户名存在,重新注册。
不存在:注册账号,返回登录页面。
需要一个查询语句(查询用户名是否存在),一个添加账号语句(除去查询,都需要提交事务)

- 用户在注册页面输入用户名和密码,验证码,提交请求给RegisterServlet
- 在RegisterServlet中接收请求和数据[用户名和密码和验证码]
- 在界面层判断验证码,过了进行下面判断,不过直接返回注册页面
- 在RegisterServlet中通过Mybatis实现调用UserMapper来根据用户名查询数据库表
- 将查询的结果封装到User对象中进行返回
- 在RegisterServlet中判断返回的User对象是否为null
- 如果为null,说明根据用户名可用,则调用UserMapper来实现添加用户
- 如果不为null,则说明用户不可以,返回"用户名已存在"数据给前端
代码实现
mapper
查询用户名和添加账号两个SQL直接写
public interface UserMapper {
// 查询是否用户名存在 @Select("select * from tb_user where username=#{username}") User selectName(String username); // 添加用户名,密码 @Insert("INSERT into tb_user(username,password) VALUES (#{username},#{password})") int insertNP(User user); }
逻辑层
写两个方法,一个验证用户名,一个添加账号
讯享网public class UserService {
// 获取数据库连接方式 private SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory(); // 查询数据库用户名是否存在 public User selectName(String username) {
// 获取数据库连接 SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.selectName(username); } //添加数据,注册账号 public int inster(User user) {
SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 返回影响行数 int i = mapper.insertNP(user); sqlSession.commit();// 提交事务 return i; } }
代码分析:添加数据方法返回int,添加成功 mapper.insertNP(user)返回影响行数,若是返回0,就是没有添加。
界面层
接收注册的用户名和密码,验证码,调用逻辑层代码进行判断。
把数据库里面的验证码和前端传来的验证码进行对比。
判断用户名是否存在,存在:直接返回注册页面重新注册,给出提示。
不存在:添加账号,返回登录页面。
// 注册 @WebServlet("/registerServlet") public class RegisterServlet extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8"); //1. 接收用户数据 String username = request.getParameter("username"); String password = request.getParameter("password"); String checkCode = request.getParameter("checkCode"); //验证码 // 先判断验证码是否正确,再进行用户名重复判断 HttpSession session = request.getSession(); String yzm = (String) session.getAttribute("yzm"); if(!yzm.equalsIgnoreCase(checkCode)){
// 如果不相等,直接结束判断,重新输入 // 验证码错误,忽略大小写 request.setAttribute("register_msg","验证码错误,请重新输入"); // 转发到注册页面 request.getRequestDispatcher("/register.jsp").forward(request,response); return;// 不再往下执行 } //封装用户对象 User user = new User(); user.setUsername(username); user.setPassword(password); UserService service = new UserService(); User user1 = service.selectName(username); if( user1 == null){
// 用户名不存在,添加用户 返回提示信息和登录页面 service.inster(user); request.setAttribute("login_msg","注册成功啦,请登录"); // 转发到登录页面 request.getRequestDispatcher("/login.jsp").forward(request,response); }else {
// 用户名存在,给出提示信息 request.setAttribute("register_msg","此用户名已存在,请重新注册"); // 转发到注册页面 request.getRequestDispatcher("/register.jsp").forward(request,response); } } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response); } }
代码分析:
- 请求有中文。处理中文乱码
讯享网 request.setCharacterEncoding("utf-8");
- 验证码输入正常业务场景需要省略大小写
// 从数据库中取数据(验证码) HttpSession session = request.getSession(); String yzm = (String) session.getAttribute("yzm"); // 验证码对比,忽略大小写 if(!yzm.equalsIgnoreCase(checkCode)){
// 如果不相等,直接结束判断,重新输入 // 业务代码... return;// 不再往下执行 }
工具类(验证码)
util中:
讯享网/ * 生成验证码工具类 */ public class CheckCodeUtil {
public static final String VERIFY_CODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static Random random = new Random(); / * 输出随机验证码图片流,并返回验证码值(一般传入输出流,响应response页面端,Web项目用的较多) * * @param width 图片宽度 * @param height 图片高度 * @param os 输出流 * @param verifySize 数据长度 * @return 验证码数据 * @throws IOException */ public static String outputVerifyImage(int width, int height, OutputStream os, int verifySize) throws IOException {
String verifyCode = generateVerifyCode(verifySize); outputImage(width, height, os, verifyCode); return verifyCode; } / * 使用系统默认字符源生成验证码 * * @param verifySize 验证码长度 * @return */ public static String generateVerifyCode(int verifySize) {
return generateVerifyCode(verifySize, VERIFY_CODES); } / * 使用指定源生成验证码 * * @param verifySize 验证码长度 * @param sources 验证码字符源 * @return */ public static String generateVerifyCode(int verifySize, String sources) {
// 未设定展示源的字码,赋默认值大写字母+数字 if (sources == null || sources.length() == 0) {
sources = VERIFY_CODES; } int codesLen = sources.length(); Random rand = new Random(System.currentTimeMillis()); StringBuilder verifyCode = new StringBuilder(verifySize); for (int i = 0; i < verifySize; i++) {
verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1))); } return verifyCode.toString(); } / * 生成随机验证码文件,并返回验证码值 (生成图片形式,用的较少) * * @param w * @param h * @param outputFile * @param verifySize * @return * @throws IOException */ public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException {
String verifyCode = generateVerifyCode(verifySize); outputImage(w, h, outputFile, verifyCode); return verifyCode; } / * 生成指定验证码图像文件 * * @param w * @param h * @param outputFile * @param code * @throws IOException */ public static void outputImage(int w, int h, File outputFile, String code) throws IOException {
if (outputFile == null) {
return; } File dir = outputFile.getParentFile(); //文件不存在 if (!dir.exists()) {
//创建 dir.mkdirs(); } try {
outputFile.createNewFile(); FileOutputStream fos = new FileOutputStream(outputFile); outputImage(w, h, fos, code); fos.close(); } catch (IOException e) {
throw e; } } / * 输出指定验证码图片流 * * @param w * @param h * @param os * @param code * @throws IOException */ public static void outputImage(int w, int h, OutputStream os, String code) throws IOException {
int verifySize = code.length(); BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); Random rand = new Random(); Graphics2D g2 = image.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 创建颜色集合,使用java.awt包下的类 Color[] colors = new Color[5]; Color[] colorSpaces = new Color[]{
Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.YELLOW}; float[] fractions = new float[colors.length]; for (int i = 0; i < colors.length; i++) {
colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)]; fractions[i] = rand.nextFloat(); } Arrays.sort(fractions); // 设置边框色 g2.setColor(Color.GRAY); g2.fillRect(0, 0, w, h); Color c = getRandColor(200, 250); // 设置背景色 g2.setColor(c); g2.fillRect(0, 2, w, h - 4); // 绘制干扰线 Random random = new Random(); // 设置线条的颜色 g2.setColor(getRandColor(160, 200)); for (int i = 0; i < 20; i++) {
int x = random.nextInt(w - 1); int y = random.nextInt(h - 1); int xl = random.nextInt(6) + 1; int yl = random.nextInt(12) + 1; g2.drawLine(x, y, x + xl + 40, y + yl + 20); } // 添加噪点 // 噪声率 float yawpRate = 0.05f; int area = (int) (yawpRate * w * h); for (int i = 0; i < area; i++) {
int x = random.nextInt(w); int y = random.nextInt(h); // 获取随机颜色 int rgb = getRandomIntColor(); image.setRGB(x, y, rgb); } // 添加图片扭曲 shear(g2, w, h, c); g2.setColor(getRandColor(100, 160)); int fontSize = h - 4; Font font = new Font("Algerian", Font.ITALIC, fontSize); g2.setFont(font); char[] chars = code.toCharArray(); for (int i = 0; i < verifySize; i++) {
AffineTransform affine = new AffineTransform(); affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize / 2, h / 2); g2.setTransform(affine); g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10); } g2.dispose(); ImageIO.write(image, "jpg", os); } / * 随机颜色 * * @param fc * @param bc * @return */ private static Color getRandColor(int fc, int bc) {
if (fc > 255) {
fc = 255; } if (bc > 255) {
bc = 255; } int r = fc + random.nextInt(bc - fc); int g = fc + random.nextInt(bc - fc); int b = fc + random.nextInt(bc - fc); return new Color(r, g, b); } private static int getRandomIntColor() {
int[] rgb = getRandomRgb(); int color = 0; for (int c : rgb) {
color = color << 8; color = color | c; } return color; } private static int[] getRandomRgb() {
int[] rgb = new int[3]; for (int i = 0; i < 3; i++) {
rgb[i] = random.nextInt(255); } return rgb; } private static void shear(Graphics g, int w1, int h1, Color color) {
shearX(g, w1, h1, color); shearY(g, w1, h1, color); } private static void shearX(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(2); boolean borderGap = true; int frames = 1; int phase = random.nextInt(2); for (int i = 0; i < h1; i++) {
double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.95862D * (double) phase) / (double) frames); g.copyArea(0, i, w1, 1, (int) d, 0); if (borderGap) {
g.setColor(color); g.drawLine((int) d, i, 0, i); g.drawLine((int) d + w1, i, w1, i); } } } private static void shearY(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(40) + 10; // 50; boolean borderGap = true; int frames = 20; int phase = 7; for (int i = 0; i < w1; i++) {
double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.95862D * (double) phase) / (double) frames); g.copyArea(i, 0, 1, h1, 0, (int) d); if (borderGap) {
g.setColor(color); g.drawLine(i, (int) d, i, 0); g.drawLine(i, (int) d + h1, i, h1); } } } }
web调用工具类:
@WebServlet("/checkCodeServlet") public class CheckCodeServlet extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 生成验证码 ServletOutputStream os = response.getOutputStream(); String s = CheckCodeUtil.outputVerifyImage(100, 50, os, 4); // 存入session中,验证码是一存一取一验证 HttpSession session = request.getSession(); session.setAttribute("yzm",s); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response); } }
验证码是一刷新换一张,所以需要清理缓存;
在前端里面:刷新数据是带参数,形成新的页面。参数用时间显示,一秒一个。
讯享网<script> document.getElementById("changeImg").onclick = function () {
document.getElementById("checkCodeImg").src = "/checkCodeServlet?" + new Date().getMilliseconds(); } </script>
查询所有数据:
思路分析:
账号验证后,进入页面,直接展示所有数据。就是登录界面层跳转到查询所有的界面层。
查询不需要前端请求参数,直接查询,在页面展示即可。
mapper层代码
因为实体类名称有些和数据库列名不一致
需要在对应的.xml文件标注
<resultMap id="brandResultMap" type="brand"> <result column="brand_name" property="brandName"></result> <result column="company_name" property="companyName"></result> </resultMap>
讯享网public interface BrandMapper {
// 查询所有数据返回到 List集合中 @Select("select * from tb_brand") @ResultMap("brandResultMap") List<Brand> selectAll(); }
逻辑层
public class BrandService {
private SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory(); // 查询所有数据,调用对应方法(数据库) public List<Brand> selectAll() {
// 调用工具类中获取mybatis连接的方法 //获取SqlSession对象,用它来执行sql SqlSession sqlSession = sqlSessionFactory.openSession(); BrandMapper mapper = sqlSession.getMapper(BrandMapper.class); List<Brand> brands = mapper.selectAll(); sqlSession.close(); return brands; } }
页面层代码
- 正常应该是1,2,3步骤,先处理数据,然后数据转发到展示页面。
- 现在引入新技术asion结合html进行异步请求,所有是html展示,然后异步这个查询功能,直接响应数据即可,不用转发了。
- JSON是一种新的编码语言,下面详细写(需要坐标依赖)
讯享网@WebServlet("/selectAllServlet") public class SelectAllServlet extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 查询所有表单 //1. 调用BrandService完成查询 BrandService service = new BrandService(); List<Brand> brands = service.selectAll(); // 设置编码,处理中文乱码问题text/json,针对json String s = JSON.toJSONString(brands); response.setContentType("text/json;charset=utf-8"); //A. 响应数据 application/json text/json response.getWriter().write(s); //2. 存入request域中 // request.setAttribute("brands",brands); //3. 转发到brand.jsp // request.getRequestDispatcher("/brand.jsp").forward(request,response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response); } }
添加数据
brand.jsp展示数据时,有添加按钮,会跳转到添加页面:addBrand.jsp。
addBrand.jsp会把请求参数传入后端。
思路分析:
后台接收请求数据,进行封装,然后给逻辑层,逻辑层调用mapper中对应的添加功能,完成添加。

上图是做 添加 功能流程。点击 新增 按钮后,会先跳转到 addBrand.jsp 新增页面,在该页面输入要添加的数据,输入完毕后点击 提交 按钮,需要将数据提交到后端,而后端进行数据添加操作,并重新将所有的数据查询出来。整个流程如下:

接下来我们根据流程来实现功能:(使用了Ajax的ASION工具+html)就直接跳转到查询,直接跳转到展示页面,Brand.html,html自己异步请求查询即可。
代码实现
mapper层
public interface BrandMapper {
// 添加商品数据 @Insert("INSERT into tb_brand VALUES(null,#{brandName},#{companyName},#{ordered},#{description},#{status})") @ResultMap("brandResultMap") void add(Brand brand); }
逻辑层
讯享网public class BrandService {
private SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory(); // 添加商品数据 public void add(Brand brand){
SqlSession sqlSession = sqlSessionFactory.openSession(); BrandMapper mapper = sqlSession.getMapper(BrandMapper.class); mapper.add(brand); sqlSession.commit();// 提交事务 sqlSession.close(); } }
界面层
@WebServlet("/addServlet") public class AddServlet extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 处理中文乱码 request.setCharacterEncoding("utf-8"); // 获取用户信息 String brandName = request.getParameter("brandName"); String companyName = request.getParameter("companyName"); String ordered = request.getParameter("ordered"); //Integer String description = request.getParameter("description"); String status = request.getParameter("status"); //Integer Integer orderedInteger = Integer.getInteger(ordered); Integer statusInteger = Integer.getInteger(status); // 封装 Brand brand = new Brand(null, brandName, companyName, orderedInteger, description, statusInteger); BrandService service = new BrandService(); service.add(brand); // 转发 request.getRequestDispatcher("/brand.html").forward(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response); } }
修改数据
根据id修改,修改时需要显示数据(数据回显)。然后修改提交。
有待提高:可以动态修改,全部不修改不调用修改功能
mapper:
根据id修改,不可以修改id
- 回显数据,查id,返回整条数据
- 根据id修改数据
讯享网public interface BrandMapper {
//根据id回显数据 @Select("select * from tb_brand where id = #{id}") @ResultMap("brandResultMap") Brand selectId(Integer id); // 根据id修改数据 @Update("UPDATE tb_brand set brand_name = #{brandName} ,company_name = #{companyName} ," + "ordered=#{ordered},description=#{description},status=#{status} where id=#{id}") @ResultMap("brandResultMap") void updateBrand(Brand brand); }
逻辑层
public class BrandService {
private SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory(); // 修改时的回显数据 public Brand selectId(Integer id){
SqlSession sqlSession = sqlSessionFactory.openSession(); BrandMapper mapper = sqlSession.getMapper(BrandMapper.class); Brand brand = mapper.selectId(id); return brand; } // 修改商品信息 public void updateBrand(Brand brand) {
SqlSession sqlSession = sqlSessionFactory.openSession(); BrandMapper mapper = sqlSession.getMapper(BrandMapper.class); mapper.updateBrand(brand); sqlSession.commit(); sqlSession.close(); } }
页面层
回显数据代码
讯享网//修改时的回显数据 @WebServlet("/selectByIdServlet") public class SelectByIdServlet extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String id = request.getParameter("id"); Integer idInteger = Integer.parseInt(id); BrandService service = new BrandService(); Brand brand = service.selectId(idInteger); request.setAttribute("brand",brand); request.getRequestDispatcher("/update.jsp").forward(request,response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response); } }
修改数据代码
@WebServlet("/updateServlet") public class UpdateServlet extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//处理POST请求的乱码问题 request.setCharacterEncoding("utf-8"); // 获取信息 String id = request.getParameter("id"); String brandName = request.getParameter("brandName"); String companyName = request.getParameter("companyName"); String ordered = request.getParameter("ordered"); String description = request.getParameter("description"); String status = request.getParameter("status"); Integer idInteger = Integer.parseInt(id); Integer orderedInteger = Integer.parseInt(ordered); Integer statusInteger = Integer.parseInt(status); // 封装信息 Brand brand = new Brand(idInteger, brandName, companyName, orderedInteger, description, statusInteger); BrandService service = new BrandService(); service.updateBrand(brand); request.getRequestDispatcher("/brand.html").forward(request,response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response); } }
删除数据
根据id删除。
有待提高:给出提示,确认要删除吗,删除后可以查看已删除数据,永久删除等。
mapper
讯享网public interface BrandMapper {
// 根据id删除 @Delete("DELETE from tb_brand where id=#{id}") @ResultMap("brandResultMap") int dlectId(Integer id); }
逻辑层
public class BrandService {
private SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory(); // 根据id删除商品数据 public int deleteId(Integer id) {
//2. 获取SqlSession对象,用它来执行sql SqlSession sqlSession = sqlSessionFactory.openSession(); BrandMapper mapper = sqlSession.getMapper(BrandMapper.class); int i = mapper.dlectId(id); sqlSession.commit(); sqlSession.close(); return i; } }
页面层
讯享网@WebServlet("/deleteIdServlet") public class DeleteIdServlet extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String id = request.getParameter("id"); Integer i = Integer.parseInt(id); BrandService service = new BrandService(); int deleteId = service.deleteId(i); request.getRequestDispatcher("/brand.html").forward(request,response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response); } }
请求响应常见方法
request对象:
常见方法
- 获取所有参数Map集合
Map<String,String[]> getParameterMap()
- 根据名称获取参数值(数组)
讯享网String[] getParameterValues(String name)
- 根据名称获取参数值(单个值)
String getParameter(String name)
接下来,我们通过案例来把上述的三个方法进行实例演示:
1.修改req.html页面,添加爱好选项,爱好可以同时选多个
讯享网<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/request-demo/req2" method="get"> <input type="text" name="username"><br> <input type="password" name="password"><br> <input type="checkbox" name="hobby" value="1"> 游泳 <input type="checkbox" name="hobby" value="2"> 爬山 <br> <input type="submit"> </form> </body> </html>

2.在Servlet代码中获取页面传递GET请求的参数值

2.1获取GET方式的所有请求参数
/ * request 通用方式获取请求参数 */ @WebServlet("/req2") public class RequestDemo2 extends HttpServlet {
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//GET请求逻辑 System.out.println("get...."); //1. 获取所有参数的Map集合 Map<String, String[]> map = req.getParameterMap(); for (String key : map.keySet()) {
// username:zhangsan lisi System.out.print(key+":"); //获取值 String[] values = map.get(key); for (String value : values) {
System.out.print(value + " "); } System.out.println(); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
} }
获取的结果为:

2.2获取GET请求参数中的爱好,结果是数组值
讯享网/ * request 通用方式获取请求参数 */ @WebServlet("/req2") public class RequestDemo2 extends HttpServlet {
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//GET请求逻辑 //... System.out.println("------------"); String[] hobbies = req.getParameterValues("hobby"); for (String hobby : hobbies) {
System.out.println(hobby); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
} }
获取的结果为:

2.3获取GET请求参数中的用户名和密码,结果是单个值
/ * request 通用方式获取请求参数 */ @WebServlet("/req2") public class RequestDemo2 extends HttpServlet {
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//GET请求逻辑 //... String username = req.getParameter("username"); String password = req.getParameter("password"); System.out.println(username); System.out.println(password); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
} }
获取的结果为:

处理中文乱码
- 解决乱码:POST,getReader()
讯享网
request.setCharacterEncoding("UTF-8");//设置字符输入流的编码 - 解决乱码:get,获取参数的方式:getQueryString
// 乱码原因:tomcat进行URL解码,默认的字符集ISO-8859-1 /* //3.1 先对乱码数据进行编码:转为字节数组 byte[] bytes = username.getBytes(StandardCharsets.ISO_8859_1); //3.2 字节数组解码 username = new String(bytes, StandardCharsets.UTF_8);*/ username = new String(username.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
Request请求转发
- 请求转发(forward):一种在服务器内部的资源跳转方式。

(1)浏览器发送请求给服务器,服务器中对应的资源A接收到请求
(2)资源A处理完请求后将请求发给资源B
(3)资源B处理完后将结果响应给浏览器
(4)请求从资源A到资源B的过程就叫请求转发
通俗将,朋友A找我借钱,我带着A找朋友B去借钱,然后B给A钱。
- 请求转发的实现方式:
讯享网req.getRequestDispatcher("资源B路径").forward(req,resp);
- 请求转发资源间共享数据:使用Request对象
此处主要解决的问题是把请求从/req5转发到/req6的时候,如何传递数据给/req6。
需要使用request对象提供的三个方法:
- 存储数据到request域[范围,数据是存储在request对象]中
void setAttribute(String name,Object o);
- 根据key获取值
讯享网Object getAttribute(String name);
- 根据key删除该键值对
void removeAttribute(String name);
接着上个需求来:

1.在RequestDemo5的doGet方法中转发请求之前,将数据存入request域对象中
2.在RequestDemo6的doGet方法从request域对象中获取数据,并将数据打印到控制台
3.启动访问测试
(1)修改RequestDemo5中的方法
讯享网@WebServlet("/req5") public class RequestDemo5 extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo5..."); //存储数据 request.setAttribute("msg","hello"); //请求转发 request.getRequestDispatcher("/req6").forward(request,response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response); } }
(2)修改RequestDemo6中的方法
/ * 请求转发 */ @WebServlet("/req6") public class RequestDemo6 extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo6..."); //获取数据 Object msg = request.getAttribute("msg"); System.out.println(msg); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response); } }
- 请求转发的特点
- 浏览器地址栏路径不发生变化
虽然后台从
/req5转发到/req6,但是浏览器的地址一直是/req5,未发生变化

- 只能转发到当前服务器的内部资源
不能从一个服务器通过转发访问另一台服务器
- 一次请求,可以在转发资源间使用request共享数据
虽然后台从
/req5转发到/req6,但是这个只有一次请求
Response对象
- Request:使用request对象来获取请求数据
- Response:使用response对象来设置响应数据
Respones请求重定向
- 重定向方法:
讯享网resposne.sendRedirect("全部路径(模块名+路径名)"); //resposne.sendRedirect("/request-demo/resp2");
代码实现:
@WebServlet("/resp1") public class ResponseDemo1 extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("resp1...."); //重定向 resposne.sendRedirect("/request-demo/resp2"); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response); } }
- 重定向的特点
- 浏览器地址栏路径发送变化
当进行重定向访问的时候,由于是由浏览器发送的两次请求,所以地址会发生变化

- 可以重定向到任何位置的资源(服务内容、外部均可)
因为第一次响应结果中包含了浏览器下次要跳转的路径,所以这个路径是可以任意位置资源。
- 两次请求,不能在多个资源使用request共享数据
因为浏览器发送了两次请求,是两个不同的request对象,就无法通过request对象进行共享数据
介绍完请求重定向和请求转发以后,接下来需要把这两个放在一块对比下:

重定向需要全部路径,模块名,路径防止错误和修改可以直接使用方法
讯享网request.getContextPath();
//简化方式完成重定向 //动态获取虚拟目录 String contextPath = request.getContextPath(); response.sendRedirect(contextPath+"/resp2");
路径问题
问题1:转发的时候路径上没有加/request-demo而重定向加了,那么到底什么时候需要加,什么时候不需要加呢?

其实判断的依据很简单,只需要记住下面的规则即可:
- 浏览器使用:需要加虚拟目录(项目访问路径)
- 服务端使用:不需要加虚拟目录
对于转发来说,因为是在服务端进行的,所以不需要加虚拟目录
对于重定向来说,路径最终是由浏览器来发送请求,就需要添加虚拟目录。
掌握了这个规则,接下来就通过一些练习来强化下知识的学习:
<a href='路劲'><form action='路径'>- req.getRequestDispatcher(“路径”)
- resp.sendRedirect(“路径”)
答案:
讯享网1.超链接,从浏览器发送,需要加 2.表单,从浏览器发送,需要加 3.转发,是从服务器内部跳转,不需要加 4.重定向,是由浏览器进行跳转,需要加。
- 问题2:在重定向的代码中,
/request-demo是固定编码的,如果后期通过Tomcat插件配置了项目的访问路径,那么所有需要重定向的地方都需要重新修改,该如何优化?

可以在代码中动态去获取项目访问的虚拟目录,借助request对象中的getContextPath()方法,
重定向需要全部路径,模块名,路径防止错误和修改可以直接使用方法
request.getContextPath();
讯享网 //简化方式完成重定向 //动态获取虚拟目录 String contextPath = request.getContextPath(); response.sendRedirect(contextPath+"/resp2");
Response响应字符数据
要想将字符数据写回到浏览器,我们需要两个步骤:
- 通过Response对象获取字符输出流: PrintWriter writer = resp.getWriter();
- 通过字符输出流写数据: writer.write(“aaa”);
接下来,我们实现通过些案例把响应字符数据给实际应用下:
- 返回一个简单的字符串
aaa
/ * 响应字符数据:设置字符数据的响应体 */ @WebServlet("/resp3") public class ResponseDemo3 extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8"); //1. 获取字符输出流 PrintWriter writer = response.getWriter(); writer.write("aaa"); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response); } }

- 返回一串html字符串,并且能被浏览器解析
讯享网response.setHeader("content-type","text/html");
PrintWriter writer = response.getWriter();
//content-type,告诉浏览器返回的数据类型是HTML类型数据,这样浏览器才会解析HTML标签
response.setHeader("content-type","text/html");
writer.write("<h1>aaa</h1>");

==注意:==一次请求响应结束后,response对象就会被销毁掉,所以不要手动关闭流。
- 返回一个中文的字符串
你好,需要注意设置响应数据的编码为utf-8
讯享网//设置响应的数据格式及数据的编码
response.setContentType("text/html;charset=utf-8");
writer.write("你好");

总结:
响应
response.setContentType("text/html;charset=utf-8"); writer.write("aaa");
响应数据写html,识别html标签
讯享网//content-type,告诉浏览器返回的数据类型是HTML类型数据,这样浏览器才会解析HTML标签 response.setHeader("content-type","text/html");
响应中文数据,解决中文乱码
//设置响应的数据格式及数据的编码 response.setContentType("text/html;charset=utf-8");
Response响应字节数据
要想将字节数据写回到浏览器,我们需要两个步骤:
- 通过Response对象获取字节输出流:
讯享网ServletOutputStream outputStream = resp.getOutputStream();
- 通过字节输出流写数据:
outputStream.write(字节数据);
接下来,我们实现通过些案例把响应字符数据给实际应用下:
- 返回一个图片文件到浏览器
讯享网/ * 响应字节数据:设置字节数据的响应体 */ @WebServlet("/resp4") public class ResponseDemo4 extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 读取文件 FileInputStream fis = new FileInputStream("d://a.jpg"); //2. 获取response字节输出流 ServletOutputStream os = response.getOutputStream(); //3. 完成流的copy byte[] buff = new byte[1024]; int len = 0; while ((len = fis.read(buff))!= -1){
os.write(buff,0,len); } fis.close(); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response); } }
上述代码中,对于流的copy的代码还是比较复杂的,所以我们可以使用别人提供好的方法来简化代码的开发,具体的步骤是:
(1)pom.xml添加依赖
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency>
(2)调用工具类方法
讯享网//fis:输入流 //os:输出流 IOUtils.copy(fis,os);
优化后的代码:
/ * 响应字节数据:设置字节数据的响应体 */ @WebServlet("/resp4") public class ResponseDemo4 extends HttpServlet {
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 读取文件 FileInputStream fis = new FileInputStream("d://a.jpg"); //2. 获取response字节输出流 ServletOutputStream os = response.getOutputStream(); //3. 完成流的copy IOUtils.copy(fis,os); fis.close(); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response); } }





版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/31326.html