从配置Maven环境到写出第一个Maven项目_05年的程序员的博客-CSDN博客
1.回顾JDBC项目开发步骤 2.Mybatis框架sql书写位置以及dao层不方法重载的原因 3.Maven+MyBatis项目开发思路 1.建表+书写实体类①注意:实例类必须实现Serializable实现序列化
②下载lombok使用注解替代快捷键生成全参构造、无参构造、toString(可以不用,但有必要)
package com.gr.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {
private Integer id;
private String name;
private String sex;
private String tel;
private Integer age;
public Student(String name, String sex, String tel, Integer age) {
this.name = name;
this.sex = sex;
this.tel = tel;
this.age = age;
}
}
2.新建maven项目
①修改GroupID com.gr
②补全项目结构
③根据需求添加及修改配置文件引入依赖
注意:webapp一旦无蓝点证明如下标签没有在pom.xml配置,配置后点击屏幕右侧maven刷新项目
war
1.在pom.xml下引入依赖
pom.xml
4.0.0 com.gr MyBatisStudentManageProject1.0-SNAPSHOT utf-8 8 8 war mysql mysql-connector-java8.0.23 javax.servlet javax.servlet-api3.1.0 provided jstl jstl1.2 org.projectlombok lombok1.18.10 junit junit4.11 test org.mybatis mybatis3.5.4 org.slf4j slf4j-log4j121.7.30
2.resources根目录下添加设置mybatis-config.xml文件(配置文件1)
位置:main/resources
3.resources根目录下添加设置log4j.properties(配置文件2)
位置:main/resources
log4j.rootLogger=DEBUG, stdout # SqlMap logging configuration... log4j.logger.com.ibatis=DEBUG log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG log4j.logger.com.ibatis.sqlmap.engine.cache.CacheModel=DEBUG log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientImpl=DEBUG log4j.logger.com.ibatis.sqlmap.engine.builder.xml.SqlMapParser=DEBUG log4j.logger.com.ibatis.common.util.StopWatch=DEBUG log4j.logger.java.sql.Connection=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
4.resources目录下建分层com/gr/dao文件夹下加入替换daoimpl的xxxMapper.xml,用来书写sql替换书写繁琐的dao层实现类
模板3.书写dao层并测试 依照模板书写sql实现dao层方法 select s_id id,name,sex,tel,age from t_student insert into t_student values(null,#{name},#{sex},#{tel},#{age}) delete from t_student where s_id=#{id} update t_student set name=#{name},sex=#{sex},tel=#{tel},age=#{age} where s_id=#{id}
①根据需求书写dao层方法,养成习惯方法上面加文档注释
package com.gr.dao;
import com.gr.entity.Student;
import com.gr.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface StudentDao {
Student selectStudentById(Integer id);
List selectAllStudent();
void deleteStudentById(Integer id);
void insertStudent(Student student);
void updateStudent(Student student);
List selectByPage(@Param("start") int start,@Param("pageSize") int pageSize);
//查询数据库表里面有几条数据
int selectCount();
}
注意:书写完查询所有就可以写分页了,这里直接拿小帅哥总结好的分页思路!
首先正常的分页如果是第一次写可以在查询全部的表格写完后在此基础上再做修改。
需要增加的参数:从第几条开始 start,查询几条数据 , pageSize(自己定),总数据条数 allCount ,当前页数 curPage , 总页数 allPage
书写顺序:
↓
Dao层:(原查所有的方法)由于分页一页显示的是固定的条数所以需要获取limit的两个参数(从第几条开始 start,查询几条 pageSize)
↓ 实现代码:select * from 表名 limit ?,?
↓ (新增方法)用于展示获取总页数,只需获取本表一共有多少数据即可(总数据条数 allCount )
↓ 实现代码:select count(*) cou from 表名 (cou为别名可不写)
Servlet层:由于通常需要给用户显示当前页数和总页数(所以需要获取这两个参数 curPage allPage)
↓ (curPage获取思路:不管有没有先从request作用域获取,由于第一次访问所以还未进入到jsp,所以第一次一定为空,可以加一个小判断解决)
↓ 实现代码:
↓ //尝试从请求路径中获取页号,第一次获取不到,点击下一页或者上一页时候可以获取
↓ String curPageStr=req.getParameter("curPage");
↓ int curPage=1;//当前的页数默认值为1
↓ if (curPageStr!=null){
↓ curPage= Integer.parseInt(curPageStr);
↓ }
↓ (start获取思路:根据carPage和pageSize获取)
↓ 实现代码:
↓ int pageSize=3;//一页显示的条数,自定
↓ int start=(curPage-1)*pageSize;//从第几条开始显示的
↓ (allPage获取思路:可以用上面写出来的获取总条数除于一页的条数获取 ***但是,由于最后一页并不一定显示完全也就是说前面除法有余数,这个余数也是需要单独一页来展示出来的,所以我们用%来判断一下)
↓ 实现代码(根据自己的代码修改):
↓ //获取总条数
↓ int count=phoneService.allCount();
↓ //给总页数设置初始值
↓ int allPage=0;
↓ //如果除尽则为当前页面刚好可以展示全,不需要再加一页
↓ //如果除不尽则需要再添加一页来展示剩余数据
↓ if (count%pageSize==0){
↓ allPage=count/pageSize;
↓ }else {
↓ allPage=count/pageSize+1;
↓ }
↓ //总条数除于一页的条数的总页数就是总页数
↓ session.setAttribute("allPage",allPage);
jsp页面:用超链接来表示上一页下一页(如果嫌丑可以根据自己的喜好添加样式,***上面的数据记得转发过来)
↓ 这里直接展示代码:
↓ 当前是第${作用域.curPage}页 ,共${作用域.allPage}页
↓ 上一页
↓ 下一页
jsp页面优化:由于便于用户操作添加一个首页尾页,并且不再在第一页显示上一页和首页(解决逻辑问题)
↓ (当然可以根据此处逻辑根据自己的想法修改,如显示第一二三页直接跳转到指定页面)
↓ 代码展示:(用c标签的if判断解决)
↓
↓ 首页
↓ 上一页
↓
↓
↓ 下一页
↓ 尾页
↓
这是插件实现:(包自行找,这里是maven导入)
这种写法dao和业务类都比较复杂。我们可以通过mybatis的PageHelper简化我们的开发。
具体步骤:
1. 引入依赖包
com.github.pagehelper
pagehelper
5.1.11
1. 在mybatis主配置文件mybatis-config.xml中注册该插件。
要写在实体类别名下面,数据源配置的上面
2. 只要在dao里面提供查询所有的方法。
3. 调用dao的时候需要两行代码
SqlSession session = MybatisUtil.getSession();
ProductDao pd = session.getMapper(ProductDao.class);
//设置分页信息。第一个参数是页号,第二个参数是一页显示的条数
PageHelper.startPage(1, 3);
//查询全部
List proList = pd.selectAll();
//把查询全部返回的数据封装到PageInfo对象里面。
PageInfo pi=new PageInfo<>(proList);
List list = pi.getList();//获取到当前页的所有数据
pi.getNextPage();//下一页的页号
pi.getPages();//总页数
boolean hasNextPage = pi.isHasNextPage();//是否有下一页
boolean hasPreviousPage = pi.isHasPreviousPage();//是否有上一页
pi.getPageNum();//当前页号
session.close();
注意:配置mybatis-config.xml 避免dao层测试出现让人头秃的异常
②在com/gr/dao目录下,根据xxxMapper模板书写dao接口替换原来繁琐的jdbc中的sql语句,一种sql对应一种标签
select s_id id,name,sex,tel,age from t_student insert into t_student values(null,#{name},#{sex},#{tel},#{age}) delete from t_student where s_id=#{id} update t_student set name=#{name},sex=#{sex},tel=#{tel},age=#{age} where s_id=#{id} select s_id id,name,sex,tel,age from t_student where s_id=#{id} select s_id id,name,sex,tel,age from t_student limit #{start},#{pageSize} select count(*) cou from t_student
③在main同级test包下com/gr/test文件夹,新建XxxDaoTest,基于junit@Test的方式,public void TestXxx(){}
注意:不要在此测试类建主函数,建立主函数就不允许在下面写同级测试方法,失去使用junit的意义
package com.gr.test;
import com.gr.entity.Student;
import com.gr.service.StudentService;
import com.gr.service.impl.StudentServiceImpl;
import com.gr.util.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class StudentDaoTest {
@Test
public void TestSelectAll(){
SqlSession session= MyBatisUtils.openSession();
StudentService studentService=new StudentServiceImpl();
List studentList = studentService.selectAllStudent();
for (Student s:studentList
) {
System.out.println(s);
}
session.commit();
}
@Test
public void TestInsert(){
SqlSession session= MyBatisUtils.openSession();
StudentService studentService=new StudentServiceImpl();
Student student=new Student("瑞雯","女","666",16);
studentService.insertStudent(student);
session.commit();
}
@Test
public void TestDelete(){
SqlSession session= MyBatisUtils.openSession();
StudentService studentService=new StudentServiceImpl();
studentService.deleteStudentById(7);
session.commit();
}
@Test
public void TestUpdate(){
SqlSession session= MyBatisUtils.openSession();
StudentService studentService=new StudentServiceImpl();
studentService.updateStudent(new Student(6,"锐萌萌","女","665",19));
session.commit();
}
@Test
public void TestSelectById(){
SqlSession session= MyBatisUtils.openSession();
StudentService studentService=new StudentServiceImpl();
Student student=studentService.selectStudentById(6);
System.out.println(student);
session.commit();
}
}
4.书写service层
以User+student管理系统为例
package com.gr.service;
import com.gr.entity.Student;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface StudentService {
public Student selectStudentById(Integer id);
public List selectAllStudent();
public void deleteStudentById(Integer id);
public void insertStudent(Student student);
public void updateStudent(Student student);
List selectByPage(@Param("start") int start, @Param("pageSize") int pageSize);
//查询数据库表里面有几条数据
int selectCount();
}
4.1一个参数
方法:
public User selectUserById(Integer id);
mapper.xml
select user_id as userId,user_name as username,password from t_user where user_id = #{a}
一个参数时,#{}中内容可以任意,实战时#{}中保持和参数名相同。
4.2多个参数
方法:
public User selectUserByNameAndPassword(@Param("username")String name,@Param("password")String password);
mapper.xml
select user_id as userId,user_name as username,password from t_user where user_name = #{username} and password = #{password}
多个参数时,使用Param注解给参数起别名,在mapper.xml中#{}里填注解值。注意:一个参数时,也可以使用Param注解,但是一旦使用注解,#{}中必须使用注解值。
4.3对象参数
不使用Param注解时:#{}中直接使用属性名
方法:
public void updateUser(User u);
mapper.xml
update t_user set user_name = #{username}, password = #{password} where user_id = #{userId}
使用注解时:#{}中填 注解名.属性名
方法
public void updateUser(@Param("user")User u); mapper.xml
update t_user set user_name = #{user.username}, password = #{user.password} where user_id = #{user.userId}
实战时:一个参数时不用注解,多个参数时使用注解。
4.4 MyBatisUtils工具类
MyBatisUtils:抽取MyBatis编程中共性的代码。
基本思路:
第1版MyBatisUtils
public class MyBatisUtils {
//创建SqlSession
public static SqlSession openSession() {
//1 读取配置文件
InputStream in = null;
try {
in = Resources.getResourceAsStream("mybatis-config.xml");
}catch(Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
//2 创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3 创建SqlSession对象
SqlSession sqlSession= factory.openSession();
return sqlSession;
}
//关闭sqlSession
public static void close(SqlSession sqlSession) {
sqlSession.close();
}
}
优化的思路:
Resources:读取配置文件(IO读取)
建议:读取配置文件只发生一次,定义在静态代码块中
SqlSessionFactory:创建SqlSession对象
建议:重量级对象(占据更多的内存),应该保证其单例
SqlSession:封装了一个Connection
建议:保证service和dao获取到同1个sqlSession
MyBatisUtils最终版本
public class MyBatisUtils {
//2 创建SqlSessionFactory对象
private static SqlSessionFactory factory;
static {
//1 读取配置文件
InputStream in = null;
try {
in = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(in);
}catch(Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
//创建SqlSession
public static SqlSession openSession() {
//3 创建SqlSession对象
SqlSession sqlSession= factory.openSession();
return sqlSession;
}
//关闭sqlSession
public static void close(SqlSession sqlSession) {
sqlSession.close();
}
}
利用工具类的优化书写ServiceImpl,以学生管理系统业务层为例
package com.gr.service.impl;
import com.gr.dao.StudentDao;
import com.gr.entity.Student;
import com.gr.service.StudentService;
import com.gr.util.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import java.util.ArrayList;
import java.util.List;
public class StudentServiceImpl implements StudentService {
@Override
public Student selectStudentById(Integer id) {
SqlSession session=null;
Student student=null;
try {
session= MyBatisUtils.openSession();//1.获取sqlSession对象
StudentDao studentDao=session.getMapper(StudentDao.class);// 2.获取dao对象
student=studentDao.selectStudentById(id);
session.commit();
}finally {
MyBatisUtils.close(session);
}
return student;
}
@Override
public List selectAllStudent() {
SqlSession session=null;
List list=new ArrayList<>();
try {
session= MyBatisUtils.openSession();//1.获取sqlSession对象
StudentDao studentDao=session.getMapper(StudentDao.class);// 2.获取dao对象
list=studentDao.selectAllStudent();
session.commit();
}finally {
MyBatisUtils.close(session);
}
return list;
}
@Override
public void deleteStudentById(Integer id) {
SqlSession session=null;
try {
session= MyBatisUtils.openSession();//1.获取sqlSession对象
StudentDao studentDao=session.getMapper(StudentDao.class);// 2.获取dao对象
studentDao.deleteStudentById(id);
session.commit();
}finally {
MyBatisUtils.close(session);
}
}
@Override
public void insertStudent(Student student) {
SqlSession session=null;
try {
session= MyBatisUtils.openSession();//1.获取sqlSession对象
StudentDao studentDao=session.getMapper(StudentDao.class);// 2.获取dao对象
studentDao.insertStudent(student);
session.commit();
}finally {
MyBatisUtils.close(session);
}
}
@Override
public void updateStudent(Student student) {
SqlSession session=null;
try {
session= MyBatisUtils.openSession();//1.获取sqlSession对象
StudentDao studentDao=session.getMapper(StudentDao.class);// 2.获取dao对象
studentDao.updateStudent(student);
session.commit();
}finally {
MyBatisUtils.close(session);
}
}
@Override
public List selectByPage(int start, int pageSize) {
SqlSession session=null;
List studentList=null;
try {
session= MyBatisUtils.openSession();//1.获取sqlSession对象
StudentDao studentDao=session.getMapper(StudentDao.class);// 2.获取dao对象
studentList=studentDao.selectByPage(start,pageSize);
session.commit();
}finally {
MyBatisUtils.close(session);
}
return studentList;
}
@Override
public int selectCount() {
SqlSession session=null;
int n=0;
try {
session= MyBatisUtils.openSession();//1.获取sqlSession对象
StudentDao studentDao=session.getMapper(StudentDao.class);// 2.获取dao对象
n=studentDao.selectCount();
session.commit();
}finally {
MyBatisUtils.close(session);
}
return n;
}
}
5.书写jsp页面
5.1登录:
表单form action="${pageContext.request.contextPath}/login" method="post"
提交表单(button或input-submit)至LoginController(@WebServlet("/login"))
或
LoginController
package com.gr.controller;
import com.gr.entity.User;
import com.gr.service.UserService;
import com.gr.service.impl.UserServiceImpl;
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;
@WebServlet("/login")
public class LoginController extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
UserService userService=new UserServiceImpl();
//1.收参
String username= req.getParameter("username");
String password= req.getParameter("password");
//2.处理业务
User user =userService.loginByNameAndPassword(username,password);
System.out.println(user);
if (user!=null){
resp.sendRedirect(req.getContextPath()+"/selectAllStudent");
}else {
resp.sendRedirect(req.getContextPath()+"/index.jsp");
}
}
}
登录写完后,一般建议设置两个filter
1.CharSetFilter
package com.gr.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/user
HttpServletRequest request=(HttpServletRequest) servletRequest;//获取请求对象
HttpSession session =request.getSession();
HttpServletResponse response=(HttpServletResponse) servletResponse;//获取响应对象
//从session作用域中获取对应登录成功的对象
Student student=(Student) session.getAttribute("student");
if (student!=null){//如果学生对象不为空说明登录成功,放行
filterChain.doFilter(request,servletResponse);
}else {
response.sendRedirect(request.getContextPath()+"login.jsp");
}
}
@Override
public void destroy() {
}
}
5.2查询所有:
①书写SelectAllXxxController
@WebServlet("/user/findAllStudent")
package com.gr.controller;
import com.gr.entity.Student;
import com.gr.service.StudentService;
import com.gr.service.impl.StudentServiceImpl;
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;
//@WebServlet("/selectAllStudent")
public class SelectAllStudentController extends HttpServlet {
StudentService studentService=new StudentServiceImpl();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
List studentList= studentService.selectAllStudent();
req.setAttribute("studentList",studentList);
req.getRequestDispatcher("/student_list.jsp").forward(req,resp);
}
}
查询成功将集合放入request作用域并跳转至查询所有jsp将request作用域中的集合
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %>学生信息表
注意:查询所有的jsp中可以定义对页面显示的数据的增删改+批量删除
批量删除思路:
1.首先先将写好的展示所有表格用form表单包裹住,遍历展示所有数据过程中增加一个复选框用来将选中数据提交到后台


