学习 SSM框架 项目总结

通过指导老师发布的学习SSM框架项目,这次我深刻体会到了SSM整体项目之间的紧连关系。

以下是我自己学习过程中总结出来的经验。

SSM框架 配置

导入核心 spring 组件坐标

将spring相关组件坐标,导入到 pom 文件中

<!--spring、springMVC-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.6.8</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${spring.version}</version>
    </dependency>

SSM框架XML配置

随后,将SSM框架配置的XML文件放置在resource资源目录下,

其中配置过程,最好 分层 解耦 的 配置,对应软件设计原则:高内聚低耦合。

  • 内聚:软件中各个功能模块内部的功能联系
  • 耦合:衡量软件中各个层/模块之间的依赖、关联的程度

通过,我首次配置,无数次报错的经历,学习到了相关配置的标签语句含义,如下:

dao 层(Mapper所在层)的相关配置

1、引入 数据库连接 相关变量 XML

    <!--引入jdbc.properties-->
    <bean id="placeholderConfigurer" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
        <property name="locations" value="classpath:jdbc.properties"/>
    </bean>

2、引入 数据源

<!--引入c3p0数据源-->
    <bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--注入属性-->
        <property name="driverClass" value="${jdbc.driverClass}"/>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <!--初始化连接池大小-->
        <property name="initialPoolSize" value="5"/>
        <!--设置最大连接数-->
        <property name="maxPoolSize" value="50"/>
        <!--设置最小连接数-->
        <property name="minPoolSize" value="10"/>
    </bean>

    <!--引入druid数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <!--注入属性-->
        <property name="driverClassName" value="${jdbc.driverClass}"/>
        <property name="url" value="${jdbc.jdbcUrl}"/>
        <property name="username" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <!--初始化连接池大小-->
        <property name="initialSize" value="5"/>
        <!--设置最大连接数-->
        <property name="maxActive" value="20"/>
        <!--设置等待时间-->
        <property name="maxWait" value="5000"/>
    </bean>

3、声明 会话工厂 ,引用数据源, 并注入 mybatis-config.xml 配置文件

<!--声明sessionFactory 并注入mybatis.cfg.xml-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--加载mybatis的配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!--注入mapper.xml-->
        <property name="mapperLocations">
            <array>
                <value>classpath:mapper/*/*Mapper.xml</value>
            </array>
        </property>
    </bean>

4、扫描 Mapper 接口 所在的包,同时注入 会话工厂

 <!--扫描mapper接口-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--注入mapper接口所在的包-->
        <property name="basePackage" value="com.angindem.bus.mapper,com.angindem.sys.mapper,com.angindem.stat.mapper"/>
        <!--注入sqlSessionFactory-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

Service层的相关配置

1、使用 <context:component-scan base-package="path"/> 语句扫描并自动注册对应bean类

<!--扫描服务层-->
    <context:component-scan base-package="com.angindem.sys.service.impl"/>
    <context:component-scan base-package="com.angindem.bus.service.impl"/>
    <context:component-scan base-package="com.angindem.stat.service.impl"/>

2、声明 数据库的事务管理器 bean类

<!--声明事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

 <!--声明事务的传播性,spring中的通知-->
    <tx:advice id="advise">
        <tx:attributes>
            <!--以add save  update delete change  reset 这些开头的方法我们都设置事务-->
            <tx:method name="add*"/>
            <tx:method name="save*"/>
            <tx:method name="update*"/>
            <tx:method name="delete*"/>
            <tx:method name="change*"/>
            <tx:method name="reset*"/>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="load*" read-only="true"/>
            <tx:method name="*" read-only="true"/>
        </tx:attributes>
    </tx:advice>

3、编写 AOP 切面声明

<!--编写AOP-->
    <aop:config>
        <!--声明切点-->
        <aop:pointcut id="pc1" expression="execution(* com.angindem.sys.service.impl.*.*(..))"/>
        <aop:pointcut id="pc2" expression="execution(* com.angindem.bus.service.impl.*.*(..))"/>
        <aop:pointcut id="pc3" expression="execution(* com.angindem.stat.service.impl.*.*(..))"/>
        <!--编写通知,织入切点-->
        <aop:advisor advice-ref="advise" pointcut-ref="pc1"/>
        <aop:advisor advice-ref="advise" pointcut-ref="pc2"/>
        <aop:advisor advice-ref="advise" pointcut-ref="pc3"/>
    </aop:config>

Context (IOC容器)的配置

1、创建 Spring时进行包扫描并自动注册

<!--告知spring在创建容器的时候进行包扫描-->
    <context:component-scan base-package="com.angindem.sys,com.angindem.bus,com.angindem.stat"/>

2、加载 dao 和 service 的配置

    <!--加载dao的配置文件和service的配置文件-->
    <import resource="classpath:application-dao.xml"/>
    <import resource="application-service.xml"/>

springmvc 的相关配置

1、扫描并自动注册 Controller

    <!--扫描controller-->
    <context:component-scan base-package="com.angindem.sys.controller"/>
    <context:component-scan base-package="com.angindem.bus.controller"/>
    <context:component-scan base-package="com.angindem.stat.controller"/>

2、配置 映射器和适配器(允许你使用 Spring MVC 的各种注解来简化你的控制器代码,它能够处理使用 @RequestMapping 或其他相关注解的方法)

<!--配置映射器和适配器-->
    <mvc:annotation-driven />

3、配置springmvc中 解析 JSP 的视图解析器

<!--配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/view/" />
        <property name="suffix" value=".jsp" />
    </bean>

4、配置静态资源文件的放行,例如CSS等

<!--配置静态文件放行-->
    <mvc:default-servlet-handler/>

5、声明文件上传配置 的bean类

<!--配置文件上传-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--设置文件的编码-->
        <property name="defaultEncoding" value="utf-8"/>
        <!--配置文件上传支持的大小-->
        <property name="maxUploadSize" value="20971520"/>
    </bean>

最后mybatis-config相关配置,结合自己的需求,从官网中自行配置即可。

<?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>
    <settings>
        <!--配置驼峰命名-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <!--配置别名-->
    <typeAliases>
        <package name="com.angindem.domain"/>
    </typeAliases>

    <!--mybatis的分页组件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"/>
    </plugins>

</configuration>

编写习惯风格

项目整体结构

通过不同的功能进行分包,对相同类别合并,做到 高内聚低耦合,各个功能模块内部的功能联系清晰不混乱。

编写实体类

通过编写自身的实体类,其中创建 VO 对象并继承实体类,在 VO对象中创建分页视图所需的变量。

分页组件的使用

通过分页组件,获得分页查询效果。

Page<Object> page = PageHelper.startPage(menuVo.getPage(), menuVo.getLimit());

这行代码使用 PageHelper 类来启动分页查询。PageHelper 是 MyBatis 分页插件的一个工具类,它通过拦截 SQL 语句来实现物理分页。这里调用 startPage 方法来设置分页参数,其中 menuVo.getPage() 是当前页码,menuVo.getLimit() 是每页显示的记录数。

List<Menu> menus = menuMapper.queryAllMenu(menuVo);

这行代码调用 menuMapperqueryAllMenu 方法来查询所有的菜单数据。menuMapper 是一个 MyBatis 的 Mapper 接口,用于数据库操作。queryAllMenu 方法根据传入的 MenuVo 对象进行查询,返回一个 Menu 类型的列表。

return new DataGridView(page.getTotal(),menus);

这行代码创建了一个新的 DataGridView 对象,并将其返回。DataGridView 是一个自定义的响应类,用于封装分页数据。构造函数接收两个参数:page.getTotal()(总记录数)和 menus(当前页的数据列表)。

实用编写经验

人机图片验证码

引用Hutool工具坐标

 <!--hutool-->
    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>4.6.8</version>
    </dependency>

根据Hutool工具官网教程,生成验证码图片

//    生成验证码
    @RequestMapping("getCode")
    public void getCode(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {
//        定义图形的长度宽度和符号和干扰线
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(116, 36, 4, 5);
//        生成的验证码放到了 Session
        session.setAttribute("code",lineCaptcha.getCode());
//        获取输出流
        ServletOutputStream outputStream = response.getOutputStream();
//        将数据以图片的方式输出
        ImageIO.write(lineCaptcha.getImage(),"JPEG",outputStream);
    }

由于将生成的验证码答案放到了 Session 中,所以也要有个对于Web的会话管理工具类

package com.angindem.sys.utils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

public class WebUtils {
	
	public static ServletRequestAttributes getServletRequestAttributes() {
		return (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
	}
	/**
	 * 得到当前线程的请求对象
	 * @return
	 */
	public static HttpServletRequest getHttpServletRequest() {
		return getServletRequestAttributes().getRequest();
	}
	
	/**
	 * 得到当前线程的响应对象
	 */
	public static HttpServletResponse getHttpServletResponse() {
		return getServletRequestAttributes().getResponse();
	}
	
	/**
	 * 得到session对象
	 */
	public static HttpSession getHttpSession() {
		return getHttpServletRequest().getSession();
	}
	
	/**
	 * 得到servletContext对象
	 */
	public static String getServletContext() {
		return getHttpServletRequest().getServletPath();
	}
}

最后访问登录功能的时候,获取验证码进行比较

 @RequestMapping("login")
    public String login(UserVo userVo, Model model,HttpServletRequest request){
//        1、获取验证码
        String code = WebUtils.getHttpSession().getAttribute("code").toString();

        if(userVo.getCode().equals(code)){
                ....
        }
    }

登录日志文件中的获取 IP

通过用户登录的时候,我们通过在提交的请求中,访问IP存在的数据进行获取,下面是这个工具类

package com.angindem.sys.utils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import javax.servlet.http.HttpServletRequest;
/**
 * 获取用户访问ip地址
 */
public class IpUtil {
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 获取到多个ip时取第一个作为客户端真实ip
        if (StringUtils.isNotEmpty(ip) && ip.contains(",")) {
            String[] ipArray = ip.split(",");
            if (ArrayUtils.isNotEmpty(ipArray)) {
                ip = ipArray[0];
            }
        }
        return ip;
    }
}

最后,直接调用即可

 User user = userService.login(userVo);
            if(user != null){
                WebUtils.getHttpSession().setAttribute("user",user);
                
                // 构建 日志对象
                LogInfoVo logInfoVo = new LogInfoVo();
                
                // 获取 登录 IP
                String loginip = IpUtil.getIpAddress(request);
                
                String loginname = user.getLoginname();
                
                Date logintime = new Date();
                
                logInfoVo.setLoginip(loginip);
                logInfoVo.setLoginname(loginname);
                logInfoVo.setLogintime(logintime);
                
                // 调用服务添加 IP
                logInfoService.addLogInfo(logInfoVo);
                
                return "system/main/index";
            }else{
                model.addAttribute("error", SysConstant.USER_LOGIN_ERROR_MSG);
                return "system/main/login";
            }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值