前言:我们都知道Java开发web项目的框架有很多:struts,hibernate,spring,springMVC,mybatis,Ejb 。个人来说,一般的网站都会使用传统的ssh。这几天,准确是4天,要开发一个报名的系统。挺小的一个网站,只有3张表。这个时候总不能用ssh吧,杀鸡焉用宰牛刀,但是有不想使用原始的jdbc,servlet。想来想去,决定用mybatis3.2.7+struts2.1.8+bootstarp开发。
需求:用户报名。完整的界面如下:
mysql数据库:有3张表,如下
项目结构:
src的目录结构如下:
引进的jar包有:
下面具体分析src目录的代码,有mybatis的多对多查询,分页。单元测试
1.先再src目录下建立一个db.properties配置文件,存放链接数据库的参数:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/cppteam?characterEncoding=utf-8
jdbc.username=××××
jdbc.password=
2.mybatis的xml配置文件:config.xml,该文件包含对数据库的链接配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 加载属性文件 -->
<properties resource="db.properties">
</properties>
<!-- 类别名定义 -->
<typeAliases>
<package name="com.yctime.pojo"/>
</typeAliases>
<!-- 配置Mybatis的环境,事务及数据源等等 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 指定映射文件或者映射类 -->
<mappers>
<package name="com.yctime.persistence"/>
</mappers>
</configuration>
3.写pojo类
Student.java:
package com.yctime.pojo;
import java.io.Serializable;
import java.util.List;
public class Student implements Serializable {
private static final long serialVersionUID=1L;
private int id;
private String username;
private String sex;
private String classname;
private String tel;
private String power;
private String myflags;
private String introduce;
private String isfile;
private String filename;
setter getter...
Flag.java:
package com.yctime.pojo;
import java.io.Serializable;
public class Flag implements Serializable {
private static final long serialVersionUID=1L;
private int id;
private String name;
setter getter...
Selection.java:
package com.yctime.pojo;
public class Selection {
private static final long serialVersionUID=1L;
private int id;
private int studentid;
private int flagid;
setter getter...
Page.java(分页专用)
package com.yctime.pojo;
public class Page {
private int pageBegin;
private int pageGet;
setter getter...
FlagCustom.java(Flag 的拓展类,处理多对多):
package com.yctime.pojo;
import java.util.List;
public class FlagCustom extends Flag{
private List<Student> students;
setter getter...
4.写persistence层:
StudentMapper.java:(这里的接口只需声明,不需要实现,方法名看不懂没关系,呆会就明白了)
package com.yctime.persistence;
import java.util.List;
import com.yctime.pojo.Flag;
import com.yctime.pojo.FlagCustom;
import com.yctime.pojo.Page;
import com.yctime.pojo.Selection;
import com.yctime.pojo.Student;
public interface StudentMapper {
public void insertStudent(Student student);
public int getstupageCount();
public List<Student> getstudentBypage(Page page);
public Student getstudentById(int id);
public void insertSelection(Selection selection);
public void updateStudent(Student student);
public FlagCustom selectFlagStudent(int id);
public Flag getflagById(int id);
public void insertflag(Flag flag);
}
StudentMapper.xml:(id是跟上面的接口的的方法名一致,resultMap是针对多对多构建的,如果看不明白,复制里面的sql语句,放在mysql中去测试)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yctime.persistence.StudentMapper">
<resultMap type="FlagCustom" id="flagCustomMap">
<id property="id" column="id" />
<result property="name" column="name" />
</resultMap>
<resultMap type="FlagCustom" id="flagCustomStudentMap" extends="flagCustomMap">
<collection property="students" ofType="Student">
<id property="id" column="studentid" />
<result property="username" column="username" />
<result property="sex" column="sex"/>
<result property="classname" column="classname"/>
<result property="tel" column="tel"/>
<result property="power" column="power"/>
<result property="introduce" column="introduce"/>
<result property="myflags" column="myflags"/>
<result property="isfile" column="isfile"/>
<result property="filename" column="filename"/>
</collection>
</resultMap>
<insert id="insertStudent" useGeneratedKeys="true" keyProperty="id" parameterType="Student">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select last_insert_id()
</selectKey>
insert into student(username,sex,classname,tel,power,introduce,myflags,isfile,filename)
values(#{username},#{sex},#{classname},#{tel},#{power},#{introduce},#{myflags},#{isfile},#{filename})
</insert>
<select id="getstupageCount" resultType="java.lang.Integer">
select count(*) from student
</select>
<select id="getstudentBypage" parameterType="Page" resultType="Student">
select * from student where id limit #{pageBegin},#{pageGet}
</select>
<select id="getstudentById" parameterType="int" resultType="Student">
select * from student where id=#{id}
</select>
<insert id="insertSelection" parameterType="Selection">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select last_insert_id()
</selectKey>
insert into selection(studentid,flagid) values(#{studentid},#{flagid})
</insert>
<update id="updateStudent" parameterType="Student">
update student set myflags=#{myflags},isfile=#{isfile},filename=#{filename} where id=#{id}
</update>
<select id="selectFlagStudent" parameterType="int"
resultMap="flagCustomStudentMap">
select s.id as studentid,s.username as username,s.sex as sex,
s.classname as classname,s.tel as tel,s.power as power,s.introduce as introduce,
s.myflags as myflags, s.isfile as isfile,s.filename as filename,
f.id,f.name from flag f left join selection on f.id=selection.flagid left join student
s on selection.studentid=s.id where f.id=#{id}
</select>
<select id="getflagById" parameterType="int" resultType="Flag">
select * from flag where id=#{id}
</select>
<insert id="insertflag" parameterType="Flag">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select last_insert_id()
</selectKey>
insert into flag(name) values(#{name})
</insert>
</mapper>
5.写service层,其实service有没有都可以,看个人:
MybatisUtil.java是一些重量级的配置,studentService.java是针对具体的业务需求写的,主要是对persistence层的接口再次封装
MybatisUtil.java:定义一些共用的方法
package com.yctime.service;
import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MybatisUtil {
private static final String resource = "config.xml";
private static Reader reader;
private static SqlSessionFactory sqlSessionFactory;
static{
try {
reader = Resources.getResourceAsReader(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
private static final ThreadLocal<SqlSession> THREAD_LOCAL = new ThreadLocal<SqlSession>();
public static SqlSession getcurrentSession(){
SqlSession session = THREAD_LOCAL.get();
if(session==null){
session = sqlSessionFactory.openSession();
THREAD_LOCAL.set(session);
}
return session;
}
public static void closeSession(){
SqlSession session = THREAD_LOCAL.get();
THREAD_LOCAL.set(null);
if(session!=null){
session.close();
}
}
}
studentService.java:方法是上面的persistence层的StudentMapper.java的方法的封装,方法名也很像,每个方法名多个S
package com.yctime.service;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.yctime.persistence.StudentMapper;
import com.yctime.pojo.Flag;
import com.yctime.pojo.FlagCustom;
import com.yctime.pojo.Page;
import com.yctime.pojo.Selection;
import com.yctime.pojo.Student;
public class studentService {
//存储student
public void insertSStudent(Student student){
SqlSession session=MybatisUtil.getcurrentSession();
StudentMapper mapper=session.getMapper(StudentMapper.class);
mapper.insertStudent(student);
session.commit();
MybatisUtil.closeSession();
}
//获取student的页数
public int getSstupageCount(int pageSize){
SqlSession session=MybatisUtil.getcurrentSession();
StudentMapper mapper=session.getMapper(StudentMapper.class);
int pageCount=mapper.getstupageCount();
MybatisUtil.closeSession();
return ((pageCount-1)/pageSize)+1;
}
//对student分页获取数据
public List<Student> getSstudentByPage(int pageSize,int pageNow){
SqlSession session=MybatisUtil.getcurrentSession();
StudentMapper mapper=session.getMapper(StudentMapper.class);
Page page=new Page();
page.setPageBegin((pageNow-1)*pageSize);
page.setPageGet(pageSize);
List<Student> studentlist=mapper.getstudentBypage(page);
MybatisUtil.closeSession();
return studentlist;
}
//通过id获取student
public Student getSstudentById(int id){
SqlSession session=MybatisUtil.getcurrentSession();
StudentMapper mapper=session.getMapper(StudentMapper.class);
Student student=mapper.getstudentById(id);
MybatisUtil.closeSession();
return student;
}
//插入selection记录
public void insertSSelection(Selection selection){
SqlSession session=MybatisUtil.getcurrentSession();
StudentMapper mapper=session.getMapper(StudentMapper.class);
mapper.insertSelection(selection);
session.commit();
MybatisUtil.closeSession();
}
//更新student
public void updateSStudent(Student student){
SqlSession session=MybatisUtil.getcurrentSession();
StudentMapper mapper=session.getMapper(StudentMapper.class);
mapper.updateStudent(student);
session.commit();
MybatisUtil.closeSession();
}
//根据方向查找到所有选择的学生
public FlagCustom selectSFlagStudent(int id){
SqlSession session=MybatisUtil.getcurrentSession();
StudentMapper mapper=session.getMapper(StudentMapper.class);
FlagCustom falgcustom=mapper.selectFlagStudent(id);
MybatisUtil.closeSession();
return falgcustom;
}
//通过id获取flag
public Flag getSflagById(int id){
SqlSession session=MybatisUtil.getcurrentSession();
StudentMapper mapper=session.getMapper(StudentMapper.class);
Flag flag=mapper.getflagById(id);
MybatisUtil.closeSession();
return flag;
}
//存储flag
public void insertSflag(Flag flag){
SqlSession session=MybatisUtil.getcurrentSession();
StudentMapper mapper=session.getMapper(StudentMapper.class);
mapper.insertflag(flag);
session.commit();
MybatisUtil.closeSession();
}
}
6.写测试类
再测试的方法上加个@Test即可
package com.yctime.test;
import java.util.List;
import org.junit.Test;
import com.yctime.pojo.Flag;
import com.yctime.pojo.FlagCustom;
import com.yctime.pojo.Selection;
import com.yctime.pojo.Student;
import com.yctime.service.MybatisUtil;
import com.yctime.service.studentService;
public class textMapper {
public void teststudentMapper(){
Student student=new Student();
student.setClassname("XXXX");
student.setIntroduce("XXXX");
student.setPower("Hello world.");
student.setSex("XXXX");
student.setTel("XXXX");
student.setUsername("XXXX");
student.setMyflags("XX");
student.setIsfile("XX");
student.setFilename("XX");
studentService studentser=new studentService();
studentser.insertSStudent(student);
}
public void testgetpagecount(){
studentService studentser=new studentService();
int pagecount=studentser.getSstupageCount(2);
System.out.println("pagecount-->"+pagecount);
}
public void teststudentByPage(){
studentService studentser=new studentService();
List<Student> studentlist=studentser.getSstudentByPage(3, 2);
System.out.println("studentlist.size()-->"+studentlist.size());
for(int i=0;i<studentlist.size();i++)
{
System.out.println(studentlist.get(i).getId()+"-->"+studentlist.get(i).getMyflags());
}
}
public void testgetstuById(){
studentService studentser=new studentService();
Student student=new Student();
student=studentser.getSstudentById(13);
System.out.println(student.getId()+"-->"+student.getMyflags());
}
public void testinsertSSelection(){
studentService studentser=new studentService();
Selection selection=new Selection();
selection.setFlagid(1);
selection.setStudentid(23);
studentser.insertSSelection(selection);
}
public void testselectSFlagStudent(){
studentService studentser=new studentService();
FlagCustom flagcustom=studentser.selectSFlagStudent(8);
System.out.println(flagcustom.getName());
System.out.println("*******************");
for(Student student:flagcustom.getStudents())
{
System.out.println(student.getUsername());
}
}
@Test
public void testgetSflagById(){
studentService studentser=new studentService();
Flag flag=studentser.getSflagById(6);
System.out.println(flag.getName());
}
}
至此,mybatis的工作完成了
下面看看struts的
7.web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
8.在src目录下建一个struts.xml文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.action.extension" value="do,action"/>
<constant name="struts.multipart.maxSize" value="104857600"/>
<package name="register" namespace="/" extends="json-default">
<action name="student_*" class="com.yctime.web.Action.registerAction" method="{1}">
<result name="registered">/WEB-INF/signup.jsp</result>
<result name="addedflag">/addflag.jsp</result>
</action>
<action name="admin_*" class="com.yctime.web.Action.adminAction" method="{1}">
<result name="loginsuccess">/WEB-INF/adminmanager.jsp</result>
<result name="loginfail">adminlogin.jsp</result>
<result name="gostudent">/WEB-INF/student.jsp</result>
<result name="otherStudent">/WEB-INF/adminmanager.jsp</result>
<result name="flagFilter">/WEB-INF/filter.jsp</result>
<result name="studentFlagfilter">/WEB-INF/student_flagfilter.jsp</result>
</action>
</package>
</struts>
至此,struts也好了,具体的使用看具体需求了,mybatis和struts的交叉就是Action层,需要什么数据就在service中调,需要带数据跳到哪个界面就根据struts.xml去跳转
下面具体分析多对多和分页:
分页先来:
在StudentMapper.xml有一分页:
<select id="getstudentBypage" parameterType="Page" resultType="Student">
select * from student where id limit #{pageBegin},#{pageGet}
</select>
它对应的方法是StudentMapper.java的public List<Student> getstudentBypage(Page page);这里传入的参数是一个Page对象,看看Page对象先,他有两个成员变量:pageBegin 和 pageGet,分别代表从第几行记录和要取多少记录。再看看public int getstupageCount();,看看它对用应的sql语句:
<select id="getstupageCount" resultType="java.lang.Integer">
select count(*) from student
</select>
很明显,他是取得该分页表的记录行,public int getstupageCount();在service层中被下面的方法调用:
//获取student的页数
public int getSstupageCount(int pageSize){
SqlSession session=MybatisUtil.getcurrentSession();
StudentMapper mapper=session.getMapper(StudentMapper.class);
int pageCount=mapper.getstupageCount();
MybatisUtil.closeSession();
return ((pageCount-1)/pageSize)+1;
}
传入的参数代表一页要显示几条数据,根据得到记录的总数,用
((pageCount-1)/pageSize)+1
计算出页数。
再看看service层的另一个方法:
//对student分页获取数据
public List<Student> getSstudentByPage(int pageSize,int pageNow){
SqlSession session=MybatisUtil.getcurrentSession();
StudentMapper mapper=session.getMapper(StudentMapper.class);
Page page=new Page();
page.setPageBegin((pageNow-1)*pageSize);
page.setPageGet(pageSize);
List<Student> studentlist=mapper.getstudentBypage(page);
MybatisUtil.closeSession();
return studentlist;
}
传入的参数代表一页显示的页数和当前页是第几页,根据mysql limit分页的要求,构建Page对象,于是取得想要的当前页的一页的数据,那么service层中得到的页数和取得的当前页数据有什么用呢?具体怎么用
我们看看Action层的一个方法:
String pageNow=request.getParameter("pageNow");
int s_pageNow=1;
if(pageNow!=null)
{
s_pageNow=Integer.parseInt(pageNow);
}
studentService stuService=new studentService();
int pageCount=stuService.getSstupageCount(20);
List<Student> studentlist=stuService.getSstudentByPage(20,s_pageNow);
request.setAttribute("pageCount", pageCount);
request.setAttribute("studentlist", studentlist);
return "otherStudent";
这个方法中,getSstupageCount(20);代表传入每页20条数据,返回有几页,好把页数传给前端界面显示,.getSstudentByPage(20,s_pageNow);传入20,当前页数,当前页数是变量。可以根据前端界面返回的数值切换,20告诉service层要20条数据:看看具体在jsp页面的用法:
<ul class="pagination">
<li><a href="${pageContext.request.contextPath }/admin_otherStudent.action?pageNow=1">首页</a></li>
<c:forEach begin="1" end="${pageCount}" var="i">
<li><a href="${pageContext.request.contextPath }/admin_otherStudent.action?pageNow=${i}">${i}</a></li>
</c:forEach>
<li><a href="${pageContext.request.contextPath }/admin_otherStudent.action?pageNow=${pageCount}">尾页</a></li>
</ul>
当前页数是可以返回给后台切换的。
先面说说多对多,这个比较简单,从hiberbate的角度分析:
student可以选多个flag,flag可以有多个student,selection只是用来记录两个表之间的每一个联系,回想一下hibernate的对应关系,记不记得Set,如果是hibernate,那么student中一定有Set<Selection>,flag也有。
现在一取出某个flag对应的所有学生:只需在falg的基础上加一个List<Student>,于是,flagCustom应运而生,根据mybatis3.0以后出的collection,再使用resultMap构建即可。