一篇教会你一个SSM整合的图书管理系统

222 阅读7分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情 完整项目会在末尾附上gitee链接

SSM 项目基础环境搭建

本实验将完成 SSM 整合的第一部分即完成 SSM 项目的基础环境搭建工作。本次实验项目采用三层架构 + MVC 设计模式进行搭建。实验中采用如下技术栈:

  • Spring
  • SpringMVC
  • MyBatis Plus 第三方插件
  • Druid 数据源
  • Apache IO 组件
  • Log4j 日志框架
  • JSR-303 验证框架
  • MySQL 数据库
  • JSP
  • jQuery

知识点

  • 基本环境搭建流程
  • 配置文件关联关系

第一步:新建·文件

image.png

第二步:导入依赖

按技术栈要求在 pom.xml 导入完整 SSM 的依赖,包括 mybatis plus,springmvc,jackson ,commons-io,hibernate-validator。

编写空白 applicationContext.xml

。。
    <!--引入其它配置文件到spring框架 由spring框架统一管理-->
    <import resource="spring-mybatis.xml"/>
    <import resource="spring-mvc.xml"/>
    <!--<import resource="spring-shiro.xml"/>-->
    <!--整合事务-->
    <bean id="transactionManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="dataSource"/>
    </bean>
    <!--事务配置增强-->
    <tx:advice id="txAdvice" transaction-manager="transactionManger">
        <tx:attributes>
            <!--propagation事务的传播特性,required没有事务就创建一个 有就加入-->
            <!--<tx:method name="select*" read-only="true"></tx:method>-->
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!--aop配置-->
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* org.yamiya.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
</beans>

编写 springmvc.xml,配置项目所需的基本配置,并在其中通过 import 引用 applicationContext.xml

。。

    <context:component-scan base-package="org.yamiya.controller"/>
    <!-- 适配器和映射器 -->
    <mvc:annotation-driven conversion-service="myconverter"/>
    <!-- 日期转换器 -->
    <bean id="myconverter" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="org.yamiya.util.MyDateConverter"/>
            </set>
        </property>
    </bean>
    <mvc:resources mapping="/static/**" location="/static/"/>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

        <property name="prefix" value="/WEB-INF/jsp/"/>

        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

第六步 编写日志和数据库连接信息的 properties 配置文件

driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
username = 你的用户名
password = 你的密码

第七步 编写测试类并测试(Spring 整合持久层)

这里为了方便,我们先完成全查功能。书写对应的数据库,并且照数据库字段,书写pojo里面的实体类,Book.Java,在Java下mapper里面的BookMapper书写接口方法,并且在resource同名路径的BookMapper.Xml下进行《select》配置,书写service,此处我们同样一个接口,一个类(需要使用到BookMapper。Java对象,使用对象调用方法),书写controller new一个ModeAndView对象,配置一个service对象,把service调用方法返回值传入modeandview对象。最后通过modeandview的setViewName(“路径“)跳转到我们的查询界面。书写查询界面: 通过${}获取传入的值;此处需要循环,即我们var代表循环体内对象  items谁被循环  varstaus 变量状态,主要是编号

    <c:forEach var="b" items="${blist}" varStatus="vs">
<tr>
            <td>${vs.count}</td>
         ,,,,

注意:这里我们获取时间会出现问题,需要使用类型转换才能变成我们熟悉的

<td>
                <fmt:formatDate value="${b.chubantime}" pattern="yyyy-MM-dd HH:mm:ss"/>
            </td>

到这里,项目环境搭建完成

image.png

前端代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--<%@taglib prefix="c"% uri="http://java.sun.com/jstl/core_rt"%>--%>
<%@taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %>
<html>
<head>
    <title>Title</title>
</head>
<%--工程名 webapp--%>
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/bootstrap3.3.7/css/bootstrap.css">

<body>
<table class="table table-bordered table-hover">
    <tr>
<%--         无法访问情况 (全路径也是) web-inf受保护,不能直接访问 <a class="checkbox" href="add.jsp">添加 </a>--%>
    <a class="btn btn-primary" href="${pageContext.request.contextPath}/book/add">添加 </a>

<%--        </td>--%>

    </tr>
    <tr>
        <td>编号: </td>
        <td>书名: </td>>
        <td>作者: </td>
        <td>出版社:</td>
        <td>时间: </td>
        <td>操作: </td>
    </tr>
    <%--    var代表循环体内对象  items谁被循环  varstaus 变量状态,主要是编号--%>
    <c:forEach var="b" items="${p.list}" varStatus="vs">
        <tr>
            <td>${vs.count}</td>
            <td>${b.uname}</td>>
            <td>${b.auther}</td>
            <td>${b.chubanshe}</td>
<%--            <td>${b.chubantime}</td>--%>
            <td>
                <fmt:formatDate value="${b.chubantime}" pattern="yyyy-MM-dd HH:mm:ss"/>
            </td>
<td>
    <a class="btn btn-success" href="bookbyid?id=${b.id}"> 修改</a>

    <a class="btn btn-info" href="deleteBook?id=${b.id}"> 删除</a>
</td>
        </tr>
    </c:forEach>
</table>
</body>
</html>

可以发现,这里我有一些样式。

关于怎么有样式:

这里我们使用 bootstrap,具体百度改关键词,然后在前端界面通过link引入样式,之后就能在元素里面通过一些关键语句添加样式。

怎么添加数据

整合的基础上,我们对mapper进行方法添加,和insert标签书写,然后在service里面通过mapper对象调用方法返回值,最后在controlle获取值,通过ifelse完成跳转。

然后书写我们add界面

在query跳转到add不能直接写

在web编程规范中,WEB-INF文件夹下面的内容不能直接通过文件的全路径进行访问,是受保护的。所以一般我们也会把我们的页面为了安全起见,放在我们的WEB-INF文件夹中。需要借助control,页面通用跳转

//    页面通用
    @RequestMapping("{page}")
    public String toPage(@PathVariable()String page){
        return page;
    }

注意:add这个时候我们不能跳转,会报错400

出现400的错误码

原因:我们从前端页面上获取的参数实质上都是String类型

我们数据库中的使用类型叫做datatime类型 我在java中封装的数据模型的时间类型是java.util.Date类型。Mybatis在做数据转换的时候,是先把数据库中的datatime类型转为java.sql.Date类型,由于java.sql.Date是java.util.Date的子类,所以可以无风险的向上转型,所以我们查询的时候,不会有异常。但是添加的时候,从前端获取的数据都是字符串,没法转换成java.util.Date的类型,所以会出现400的错误码。

image.png

删除数据

删除最简单

不过分逻辑删除和物理删除。物理删除是真实删除,但是在生活里面很少使用,逻辑删除就比如我进行了一个购物订单,那么数据库里面订单字段有,订单编号,商品编号,用户编号,用户姓名,收货人信息(很多不列举),状态码。

其中对于逻辑删除来说,状态码最重要:

比如:我们可以约定

状态码-1:表示下单了,没有付款

2:下单了付款了,没有发货

3:已经发货

4:退款订单

5:删除订单

我们在前端看到的页面就是数据库操作当状态码等于xx的时候的值,具体在mapperxml里面完成

搜先在bookmapper。Java里面写一个 image.png 然后去mapperxml写

image.png

然后在service里面书写接口和实现类,实现了所有mapper对象调用删除方法

然后去controller写相关方法!

image.png

最后在query。Jsp页面的删除按钮那边加上地址。

image.png

修改

修改分两步,第一步点击修改,回显当前id的内容,第二步进行修改回到全查界面

第一步:

点击某一个然后修改,类似查询全部,不过把全部改成一个,具体如截图 bookmapper.java

image.png

bookmapper.xml

image.png bookservice

image.png bookSeviceimpl

image.png bookController

image.png update.jsp

image.png

第二步:修改 按照同样的bookmapper,bookservice,bookconteoller方法进行修改的填写

修改之前:

image.png

修改之后:

image.png

登录

只有账号密码在数据库类名,才能登录,登录成功才能进行book操作。

分析:登录如何验证?其实相当于在前端页面输入,然后去数据库类名查询有没有对应当前账号密码的行,如果有,表示可以登录,如果没有,表示账号密码没找到。 所以先书写查询一个的例子。具体步骤参考book。 mapper。xml

<mapper namespace="org.yamiya.mapper.UserMappre">
   <select id="loginUser" resultType="userinfo">
       select * from userinfo where uname=#{uname} and upwd=#{upwd}
   </select>
</mapper>

controller如下:

先自动注入我们需要的的service接口对象

@Autowired
private UserService userService;

然后在登录逻辑类中通过该对象调用方法赋值,并且把值传入ModelANdView对象然后通过对象跳转网页。 到这里简单的通过登录,去到book全查页面完成。

那么开始第二个问题,只有登录才能查询到book,并且进行操作。

就需要我们引入一个过滤器

Servlet、listenner、Filter被称为web的三大核心组件。

  拦截器其实就是filter,主要的功能是过滤url。

  在ssm框架中,我们会使用Filter的子接口。功能更为强大。

首先,在spring-mvc下:

image.png 按照路径建立相关文件。

如何过滤?

首先实现 HandlerInterceptor接口,重写接口里面的preHandle方法 通过获取页面url,uri得到我们的路径,然后通过查询路径是否包含我们目的界面,如果包括,就返回true即不拦截,如果吧包括,就进行拦截

web系统的4个作用域

Application:全局作用域,作用范围在整个项目,项目一旦看是运行,该作用域就存在,项目停止运行后,该作用域消失。

Request:请求作用域,作为范围是在发生请求后,请求结束后,该作用域消失。

Session:会话作用域,作用范围是产生会话后,会话结束后,该作用域消失。或者session失效了,该作用域也会消失。

Page:当前页面作用域,只针对当前页面有效。

如何判定用户是否为登录状态?

我们会根据session里面的用户信息进行判断,如果为null,则证明是非登录状态,进行相关跳转

到这里基本的登录后才能查看完成了。

我们知道数据库一般很多数据,如何实现分页操作?

为什么分页:分页的好处缓解了数据库的压力以及网络传输的压力

 如果数据量比较大的情况,我们全查所有信息,需要等的时间就比较久。

 用户体验不好,另外如果数据量较大,你的网络传输时间比较长,一旦出现网络波动或者数据丢包的情况,数据就不能完整显示

即:在mybatis-config加入分页插件

修改bookservice类名的全查 PageInfo<Book> selectAll(int pageNum,int pageSize);

并且对应写出全查的实现

image.png

image.png 并且在jquery里面书写分页器

image.png 结果如下 image.png

完整代码如下:gitee.com/dingxianliu…