在哔哩哔哩上观看的视频,视频地址——SSM框架课程导读_哔哩哔哩_bilibili
我的项目所使用的软件版本
idea2022.2 navicat(mysql8.0) Tomcat9.0.65
项目所用到的资源
链接:https://pan.baidu.com/s/1QBV9bFVFDMJQ1pXolFsW-A?pwd=ssm1
提取码:ssm1
以下就是跟做实验的详细步骤
目录
新建applicationContext_dao.xml文件,进行数据访问层的配置
新建applicationContext_service.xml文件,进行业务逻辑层的配置
新建springmvc.xml文件,配置springmvc的框架
新建sqlMapConfig.xml文件,进行分页插件的配置
工程的环境搭建
搭建ssm项目的步骤:
新建maven工程
修改目录,修改pom.xml文件
创建出来的新项目需要添加补齐文件,比如src/main目录下的java文件和test文件
在Java中添加将要使用的包,mapper和pojo包不需要添加,之后通过逆向工程将实体类导入进去
添加ssm框架的所有依赖
需要的依赖全部都写在这里了
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima.heima-ssm</groupId>
<artifactId>heima-ssm</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<!-- 集中定义依赖版本号 -->
<properties>
<junit.version>4.12</junit.version>
<spring.version>5.2.5.RELEASE</spring.version>
<mybatis.version>3.5.1</mybatis.version>
<mybatis.spring.version>1.3.1</mybatis.spring.version>
<mybatis.paginator.version>1.2.15</mybatis.paginator.version>
<mysql.version>8.0.22</mysql.version>
<slf4j.version>1.6.4</slf4j.version>
<druid.version>1.1.12</druid.version>
<pagehelper.version>5.1.2</pagehelper.version>
<jstl.version>1.2</jstl.version>
<servlet-api.version>3.0.1</servlet-api.version>
<jsp-api.version>2.0</jsp-api.version>
<jackson.version>2.9.6</jackson.version>
</properties>
<dependencies>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</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-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis.spring.version}</version>
</dependency>
<dependency>
<groupId>com.github.miemiedev</groupId>
<artifactId>mybatis-paginator</artifactId>
<version>${mybatis.paginator.version}</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>${pagehelper.version}</version>
</dependency>
<!-- MySql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- JSP相关 -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<scope>provided</scope>
<version>${jsp-api.version}</version>
</dependency>
<!-- Jackson Json处理工具包 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20140107</version>
</dependency>
<!-- 文件异步上传使用的依赖-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
<!-- 插件配置 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
<!--识别所有的配置文件-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
创建jdbc.porpertise到resource目录下
jdbc.porpertise 文件,用来编写连接mysql数据库的信息,方便修改数据库信息直接在这修改。
密码和账号修改成自己的,还有数据库的名称。
jdbc.url中数据库名称后面的代码最后就不要做修改,表示数据库的地区的时区什么之类的。
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/xiaomissm?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
jdbc.username=root
jdbc.password=liang7728
新建applicationContext_dao.xml文件,进行数据访问层的配置
数据库连接池连接jdbc.properties。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 属性文件的读取,读取jdbc.properties文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 创建数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 创建sqlSessionFactoryBean-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 配置数据源-->
<property name="dataSource" ref="dataSource"></property>
<!-- 配置mybatis的核心配置文件-->
<property name="configLocation" value="classpath:SqlMapConfig.xml"></property>
<!-- 配置实体类-->
<property name="typeAliasesPackage" value="com.liangliang.pojo"></property>
</bean>
<!-- 创建mapper文件的扫描器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.liangliang.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
</beans>
新建applicationContext_service.xml文件,进行业务逻辑层的配置
其中在设置事务管理器中ref="dataSource"会爆红,爆红的原因是applicationContext_dao的连接池没有配入进去,可以使用文中注解的方法让他不报红,但是这样在重复查询数据库的时候可能会导致连接池重复的注入,我们可以不用管这个报错,虽然看着爆红,但是不影响编译。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--<!– 可以通过导入的方法将applicationContext_dao.xml–>-->
<!-- <import resource="classpath:applicationContext_dao.xml"></import>-->
<!-- 设置业务逻辑层的包扫描器,目的是在指定的路径下,使用@service注解的类,spring负责创建对象,并添加依赖-->
<context:component-scan base-package="com.liangliang.service"></context:component-scan>
<!-- 设置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 添加事务的切面-->
<tx:advice id="myadvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 查询的方法 只要是查询的方法就只能只读-->
<tx:method name="*select*" read-only="true"/>
<tx:method name="*find*" read-only="true"/>
<tx:method name="*get*" read-only="true"/>
<tx:method name="*search*" read-only="true"/>
<!-- 增加的话就不能是只读 让他添加事务-->
<tx:method name="*insert*" propagation="REQUIRED"/>
<tx:method name="*save*" propagation="REQUIRED"/>
<tx:method name="*add*" propagation="REQUIRED"/>
<!-- 删除的 也是添加事务-->
<tx:method name="*delete*" propagation="REQUIRED"/>
<tx:method name="*remove*" propagation="REQUIRED"/>
<tx:method name="*clear*" propagation="REQUIRED"/>
<!-- 更新-->
<tx:method name="*update*" propagation="REQUIRED"/>
<tx:method name="*modify*" propagation="REQUIRED"/>
<tx:method name="*change*" propagation="REQUIRED"/>
<tx:method name="*set*" propagation="REQUIRED"/>
<!-- 其他剩下的所有字符,让他支持事务 -->
<tx:method name="*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<!-- 完成切面和切入点的切入-->
<aop:config>
<aop:pointcut id="mypointcut" expression="execution(* com.liangliang.service.*.*(..))"/>
<aop:advisor advice-ref="myadvice" pointcut-ref="mypointcut"/>
</aop:config>
</beans>
新建springmvc.xml文件,配置springmvc的框架
在resource文件夹目录下新建springmvc.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 设置包扫描器-->
<context:component-scan base-package="com.liangliang.controller"></context:component-scan>
<!-- 设置视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/admin/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 设置文件上传的核心组件-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>
<!-- 设置注解驱动-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
配置springmvc框架,修改webapp中的一些文件
点击打开webapp/WEB-INF,删除web.xml,因为原有的web.xml 文件的头文件所引用的都是旧的一些配置
然后点击set中的ProjectStructure
然后你就能重新的得到web文件,并且里面引用的配置都是新的,如果名称是当时修改的名称,就重命名把名字改回web就ok了。
然后再web上添加字符编码过滤器 ,并对springmvc进行注册。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 添加字符编码过滤器-->
<filter>
<filter-name>encode</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encode</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 注册SpringMVC框架-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<!--
/admin/login.action
/admin/main.jsp
-->
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<!-- 注册Spring框架-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext_*.xml</param-value>
</context-param>
<welcome-file-list>
<welcome-file>/admin/login.jsp</welcome-file>
</welcome-file-list>
</web-app>
删除index.jsp文件,然后重新的添加一个index.jsp文件,因为index.jsp文件使用的头编码都是旧的或者不完整的,重新的导入可以使用新的配置。
然后我们可以将我在上面给的资料中的页面资源放进webapp文件目录下,因为主要是搞懂ssm框架的项目实战,所以就没有去写前端的页面。
新建sqlMapConfig.xml文件,进行分页插件的配置
在resource目录下新建sqlMapConfig.xml文件。这个文件的功能是将当页面在查询的商品的时候可以帮我进行分页,页面更加的美观
使用逆向工程生成pojo和mapper的文件
在给的资源中把逆向工程中的项目部署到一个不是中文路径的文件下
通过idea启动
点击打开generatorConfig.xml文件,修改里面一些配置。
让他生成的包保持一致,然后我们就可以通过GeneratorSqlmap启动类启动项目生成实体类,生成前要确保这个java包中除了启动类没有其他的包
启动成功后会自动的生成所需的 实体类
,
但是我在使用的时候似乎有点问题,就是生成的实体类中的实体名称与数据库中的不一致。他帮我生成了address中的实体类,并没有给我生成admin的实体类,这样的话可以在我的资源那把admin的实体类复制过去Admin.java,AdminMapper.java,AdminMapper.xml。
然后我们将生成好的实体类复制到项目中就行了。
正确的实体类
现阶段项目中的资源
启动项目——实现登录
开发业务逻辑层,实现登录判断
在service层中创建文件和包,进行编写登录判断的业务逻辑
AdminService 接口
package com.liangliang.service;
import com.liangliang.pojo.Admin;
public interface AdminService {
/**
* 完成登录判断
*/
Admin login(String name,String pwd);
}
AdminServiceImpl 类
package com.liangliang.service.impl;
import com.liangliang.mapper.AdminMapper;
import com.liangliang.pojo.Admin;
import com.liangliang.pojo.AdminExample;
import com.liangliang.service.AdminService;
import com.liangliang.utils.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class AdminServiceImpl implements AdminService {
/**
* 在业务逻辑层中,一定会有数据访问层的对象
*/
@Autowired
AdminMapper adminMapper;
@Override
public Admin login(String name, String pwd) {
// 根据传入的用户或到DB中查询相应的用户对象
// 如果有条件,则一定要创建admin Example的对象,用来封装条件
AdminExample example = new AdminExample();
/**
* 如何添加条件
* select * from admin where name='admin'
*/
// 添加用户名name条件
example.createCriteria().andANameEqualTo(name);
List<Admin> list = adminMapper.selectByExample(example);
if(list.size() > 0){
Admin admin = list.get(0);
// 如果查询到用户对象,再进行密码的对比,注意密码是密文的形式
/**
* 分析:
* admin.getApass==>c984aed014aec7623a54f0591da07a85fd4b762d
* pwd==>000000
* 在进行密码对比时,要将传入的pwd进行md5加密,再与数据库中查到到的对象密码进行对比
*/
// String miPwd = MD5Util.getMD5(pwd);//这个是使用了密文加密的的密码,有点麻烦吧
String miPwd = pwd; //这个是没有使用加密处理的
if (miPwd.equals(admin.getaPass())){
return admin;
}
}
return null;
}
}
解开注释的话我们就是对数据库的用户密码进行了加密处理,所以我们要获取用户在页面中输入密码时也要对输入的密码进行加密处理然后与数据库中的密码进行比对。
加密的方法写在utils包中的MD5Util类中。
package com.liangliang.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Util {
/**
* 1.MD5(message-digest algorithm 5)信息摘要算法,
* 它的长度一般是32位的16进制数字符串(如81dc9bdb52d04dc20036dbd8313ed055)
* 2.由于系统密码明文存储容易被黑客盗取
* 3.应用:注册时,将密码进行md5加密,存到数据库中,防止可以看到数据库数据的人恶意篡改。
* 登录时,将密码进行md5加密,与存储在数据库中加密过的密码进行比对
* 4.md5不可逆,即没有对应的算法,从产生的md5值逆向得到原始数据。
* 但是可以使用暴力破解,这里的破解并非把摘要还原成原始数据,如暴力枚举法。
*
*/
public final static String getMD5(String str){
try {
MessageDigest md = MessageDigest.getInstance("SHA");//创建具有指定算法名称的摘要
md.update(str.getBytes()); //使用指定的字节数组更新摘要
byte mdBytes[] = md.digest(); //进行哈希计算并返回一个字节数组
String hash = "";
for(int i= 0;i<mdBytes.length;i++){ //循环字节数组
int temp;
if(mdBytes[i]<0) //如果有小于0的字节,则转换为正数
temp =256+mdBytes[i];
else
temp=mdBytes[i];
if(temp<16)
hash+= "0";
hash+=Integer.toString(temp,16); //将字节转换为16进制后,转换为字符串
}
return hash;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
}
然后我们测试该加密方法生成的密码,在测试类中添加测试方法
package com.liangliang.test;
import com.liangliang.utils.MD5Util;
import org.junit.Test;
public class MyTest {
@Test
public void testMD5(){
String mi = MD5Util.getMD5("000000");
System.out.println(mi);
}
}
运行得到密码为000000的加密处理后的密文为c984aed014aec7623a54f0591da07a85fd4b762d
将该密文放进数据库中,放不进去可以改一下表的结构。
我们也可也不放开那个注释,不使用密文处理的方法,因为比较的麻烦。
开发控制器admin Action,完成登录
在controller包中创建AdminAction.java类
package com.liangliang.controller;
import com.liangliang.pojo.Admin;
import com.liangliang.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
@Controller
@RequestMapping("/admin")
public class AdminAction {
// 切记在所有的界面层中,一定会有业务逻辑层的对象
@Autowired
AdminService adminService;
// 实现登录判断,并进行相应的跳转
@RequestMapping("/login")
public String login(String name, String pwd, HttpServletRequest request){
Admin admin = adminService.login(name, pwd);
if (admin != null){
//登录成功
request.setAttribute("admin",admin);
return "main";
}else {
//登录失败
request.setAttribute("errmsg","用户填写的信息不正确!");
return "login";
}
}
}
登录判断中的name和pwd与前端页面的一致
然后我们通过HttpServletRequest返回用户的名字在页面跳转后打印出来
处理改造页面,发送登录请求,验证登录
添加Tomcat
然后点击应用和ok,Tomcat就配置好了,启动服务器,等待完成,进入登录页面。
输入对应数据库中admin表中的对应账号密码,登录跳转
商品列表的展示
查询所有的商品并显示
创建商品查询的接口和实现类
ProductInfoService
package com.liangliang.service;
import com.liangliang.pojo.ProductInfo;
import java.util.List;
public interface ProductInfoService {
//显示全部商品后(不分页)
List<ProductInfo> getAll();
}
ProductInfoServiceImpl
package com.liangliang.service.impl;
import com.liangliang.mapper.ProductInfoMapper;
import com.liangliang.pojo.ProductInfo;
import com.liangliang.pojo.ProductInfoExample;
import com.liangliang.service.ProductInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ProductInfoServiceImpl implements ProductInfoService {
@Autowired
ProductInfoMapper productInfoMapper;
@Override
public List<ProductInfo> getAll() {
return productInfoMapper.selectByExample(new ProductInfoExample());
}
}
创建控制类ProductInfoAction
package com.liangliang.controller;
import com.liangliang.pojo.ProductInfo;
import com.liangliang.service.ProductInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@Controller
@RequestMapping("/prod")
public class ProductInfoAction {
@Autowired
ProductInfoService productInfoService;
//显示全部商品未分页
@RequestMapping("/getAll")
public String getAll(HttpServletRequest request){
List<ProductInfo> list = productInfoService.getAll();
request.setAttribute("list",list);
return "product";
}
}
然后修改主页面的代码,就是登录后,页面调转的页面——main.jsp
然后我们来到product.jsp中修改一下代码,将foreach中的info去掉。
重新的启动项目就能实现查询全部商品了
实现商品分页
功能:当前页面显示的商品集合,页码的导航显示(后台要知道总共有多少页,并当前是第几页),当前页的页码显示。
我们在ProductInfoAction 中进行页面的分页和当前页面的显示,我们使用现成的分页插件,就是当时配置项目环境时编写的sqlMapConfig.xml分页插件,
在ProductInfoService.java接口中添加分页的方法
//分页功能的实现 pageNum当前页的第几条 pageSize 页面需要多少条数据
PageInfo splitPage(int pageNum,int pagerSize);
在ProductInfoServiceImpl.java中编写分页的业务逻辑层
在product.jsp修改代码,将上面删掉的info重新加上去,进行分页处理,
然后在controller层中的productionAction.java类中添加分页查询
// 显示分页第一页的五条数据
@RequestMapping("/split")
public String split(HttpServletRequest request){
// 得到第一页的数据
PageInfo info = productInfoService.splitPage(1,PAGE_SIZE);
request.setAttribute("info",info);
return "product";
}
将main.jsp的数据显示修改成分页显示的路径
重新启动服务器,商品列表实现了分页了,但是现在只是实现了分页显示的功能还没实现分页显示商品的功能。
通过ajax实现分页跳转功能
在product.jsp页面中添加ajax分页的方法功能
<!--分页的AJAX实现-->
<script type="text/javascript">
function ajaxsplit(page) {
//向服务器发出ajax请求,请示page业中的所有数据,在当前页面上局部刷新显示
//异步ajax分页请求
$.ajax({
url:"${pageContext.request.contextPath}/prod/ajaxSplit.action",
data:{"page":page},
type:"post",
success:function () {
//重新加载分页显示的组件table
//location.href---->http://localhost:8080/admin/login.action
$("#table").load("${pageContext.request.contentType}/admin/product.jsp #table");
}
})
};
</script>
然后在controller层中的productionAction.java类中添加分页查询的功能。
// ajax分页翻页处理
@ResponseBody
@RequestMapping("/ajaxSplit")
public void ajaxSplit(int page, HttpSession session){
// 取得当前page参数的页面的数据
PageInfo info = productInfoService.splitPage(page,PAGE_SIZE);
session.setAttribute("info",info);
}
这里为什么要使用httpSession session 的格式呢,因为存放新pageInfo对象的request作用于已经在刷新table时被销毁了,而session作用域可以长期保存数据,所以这里必须使用session。
重新的启动项目,可以使用分页的功能了。
实现新增商品 的功能
ProductTypeService.java接口
package com.liangliang.service;
import com.liangliang.pojo.ProductType;
import java.util.List;
public interface ProductTypeService {
List<ProductType> getAll();
}
ProductTypeServiceImpl.java实现类
package com.liangliang.service.impl;
import com.liangliang.mapper.ProductTypeMapper;
import com.liangliang.pojo.ProductType;
import com.liangliang.pojo.ProductTypeExample;
import com.liangliang.service.ProductTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("productTypeService")
public class ProductTypeServiceImpl implements ProductTypeService {
@Autowired
ProductTypeMapper productTypeMapper;
@Override
public List<ProductType> getAll() {
return productTypeMapper.selectByExample(new ProductTypeExample());
}
}
编写一个监听器,实现监听器的功能
package com.liangliang.listener;
import com.liangliang.pojo.ProductType;
import com.liangliang.service.ProductTypeService;
import com.liangliang.service.impl.ProductTypeServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.util.List;
@WebListener()
public class ProductTypeListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
// 手工从spring容器中取出productTypeServiceImpl的对象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext_*.xml");
ProductTypeService productTypeService = (ProductTypeService) context.getBean("productTypeService");
List<ProductType> typeList = productTypeService.getAll();
// 放入全局应用作用域中,供新增页面,修改页面,前台的查询功能提供全部商品类别集合
servletContextEvent.getServletContext().setAttribute("typeList",typeList);
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
在addproduct.jsp中添加代码
<tr>
<td class="one">类别</td>
<td>
<select name="typeId">
<c:forEach items="${typeList}" var="type">
<option value="${type.typeId}">${type.typeName}</option>
</c:forEach>
</select>
</td>
</tr>
就可以在新增商品的页面中的类别选择中显示数据库中包含的类别
上传图片
在新增商品页面中实现上传图片的功能,点击上传文件的按钮将图片上传,然后图片的名称重新赋予一个新的名称,这样就不会在数据库中导致两个重复名称的图片,我们使用ajax异步提交实现这个功能,但是现在的图片是上传到tomcat服务器上的,当你重启服务器后图片会丢失。
实现异步ajax上传的方法 ,在body标签上面添加script标签
<script type="text/javascript">
function fileChange(){//注意:此处不能使用jQuery中的change事件,因此仅触发一次,因此使用标签的:onchange属性
alert("change");
$.ajaxFileUpload({
url: '/prod/ajaxImg.action',//用于文件上传的服务器端请求地址
secureuri: false,//一般设置为false
fileElementId: 'pimage',//文件上传控件的id属性 <input type="file" id="pimage" name="pimage" />
dataType: 'json',//返回值类型 一般设置为json
success: function(obj) //服务器成功响应处理函数
{
alert(obj);
$("#imgDiv").empty(); //清空原有数据
//创建img 标签对象
var imgObj = $("<img>");
//给img标签对象追加属性
imgObj.attr("src","/image_big/"+obj.imgurl);
imgObj.attr("width","100px");
imgObj.attr("height","100px");
//将图片img标签追加到imgDiv末尾
$("#imgDiv").append(imgObj);
//将图片的名称(从服务端返回的JSON中取得)赋值给文件本框
//$("#imgName").html(data.imgName);
},
error: function (e)//服务器响应失败处理函数
{
alert(e.message);
}
});
}
</script>
在Utils包中添加一个工具类,文件重命名的工具类FileNameUtil
package com.liangliang.utils;
import java.util.UUID;
public class FileNameUtil {
//根据UUID生成文件名
public static String getUUIDFileName() {
UUID uuid = UUID.randomUUID();
return uuid.toString().replace("-", "");
}
//从请求头中提取文件名和类型
public static String getRealFileName(String context) {
// Content-Disposition: form-data; name="myfile"; filename="a_left.jpg"
int index = context.lastIndexOf("=");
String filename = context.substring(index + 2, context.length() - 1);
return filename;
}
//根据给定的文件名和后缀截取文件名
public static String getFileType(String fileName){
//9527s.jpg
int index = fileName.lastIndexOf(".");
return fileName.substring(index);
}
}
在productAction类中编写控制方法,我们将这个savefileName作为全局变量拿出去,因为方便后面我们将图片连同表单一起上交上去
// 异步ajax文件上传处理
@ResponseBody
@RequestMapping("/ajaxImg")
public Object ajaxImg(MultipartFile pimage,HttpServletRequest request){
// 提取生成文件名 uuid+上传图片的后缀 .jpg .png
saveFileName = FileNameUtil.getUUIDFileName()+FileNameUtil.getFileType(pimage.getOriginalFilename());
// 得到项目中图片存储的路径
String path = request.getServletContext().getRealPath("/image_big");
// 转存 E:\idea_workspace\mimissm\image_big\dafasdfasdf.jpg
try {
pimage.transferTo(new File(path+File.separator+saveFileName));
}catch (IOException e){
e.printStackTrace();
}
// 返回客户端json对象,封装图片的路径,为了在页面实现立即回显
JSONObject object = new JSONObject();
object.put("imgurl",saveFileName);
return object.toString();
}
然后重启服务器,我们就可以测试上传图片回显了
表单提交的动作
在addproduct.jsp中添加代码
然后我们提交表单携带上其他的数据一起增加
// 表单提交的
@RequestMapping("/save")
public String save(ProductInfo info,HttpServletRequest request){
info.setpImage(saveFileName);
info.setpDate(new Date());
// info对象中有表单提供上来的五个数据,有异步ajax上来的图片名称数据,有上架时间的数据
int num = -1;
try {
num = productInfoService.save(info);
} catch (Exception e) {
e.printStackTrace();
}
if(num > 0){
request.setAttribute("msg","增加成功!");
}else {
request.setAttribute("msg", "增加失败!!");
}
// 清空saveFileName变量中的内容,为了下次增加或者修改的异步ajax的上传做处理
saveFileName = "";
// 增加成功后应该重新的访问数据库,所以跳转到分页显示的action上
return "forward:/prod/split.action";
}
记得写上增加商品数据的逻辑业务类
productInfoService.java接口
int save(ProductInfo info);
productInfoServiceImpl.java实现类
@Override
public int save(ProductInfo info) {
return productInfoMapper.insert(info);
}
然后运行服务器,测试添加商品
查看数据库,刚刚添加的商品信息已经添加上去了
实现更新商品信息功能
更新商品的信息查询
编写更新商品的接口类和实现类
接口类
实现类
在controller类中编写控制方法
product.jsp的代码添加
//点击商品的编辑按钮时,将页面中该商品的信息传到编辑页面中
function one(pid, ispage) {
//像服务器提交请求,传递商品id
location.href = "${pageContext.request.contextPath}/prod/one.action?pid=" + pid + "&page=" + ispage;
}
重新启动服务器,测试获取更新商品的信息
更新商品的功能实现,点击提交重新更新的信息被打印上去
productInfoService接口类
// 更新商品
int update(ProductInfo info);
productInfoServiceImpl实现类
// 更新商品信息的提交
@Override
public int update(ProductInfo info) {
return productInfoMapper.updateByPrimaryKey(info);
}
productInfoAction控制层
// 更新修改的商品信息
@RequestMapping("/update")
public String update(ProductInfo info, HttpServletRequest request){
// 因为ajax的异步图片上传,如果有上传过,则saveFileName里有上传上来的图片名称
// 如果没有使用异步ajax上传,则saveFileName的内容为空,实体类的info使用隐藏的表单提供上来的image原始图片的名称
if(!saveFileName.equals("")){
info.setpImage(saveFileName);
}
// 完成更新处理
int num = -1;
try {
num = productInfoService.update(info);
} catch (Exception e) {
e.printStackTrace();
}
if (num > 0){
// 此时更新成功
request.setAttribute("msg","更新成功!");
}else {
// 更新失败
request.setAttribute("msg","更新失败!");
}
// 处理完更新后,saveFileName里面可能有数据,
// 而下次使用这个变量作为判断的依据,就会出错,所以要清空saveFileName
saveFileName = "";
return "forward:/prod/split.action";
}
功能测试
重启服务器,修改商品信息提交之后
删除商品功能
删除单个商品
点击删除,页面弹窗提示,是否删除商品,若点击取消则返回列表无事发生,若点击确定则删除该选定的商品,并刷新页面列表,返回列表的第一页中。
productInfoService接口
// 删除商品
int delete(int pid);
productInfoServiceImpl实现类
// 删除单个商品
@Override
public int delete(int pid) {
return productInfoMapper.deleteByPrimaryKey(pid);
}
productInfoAction控制类
@RequestMapping("/delete")
public String delete(int pid,HttpServletRequest request){
int num = -1;
try {
num = productInfoService.delete(pid);
} catch (Exception e) {
e.printStackTrace();
}
if (num > 0){
request.setAttribute("msg","删除成功");
}else {
request.setAttribute("msg", "删除失败");
}
// 删除结束后跳转分页显示
return "forward:/prod/deleteAjaxSplit.action";
}
@ResponseBody
@RequestMapping(value = "/deleteAjaxSplit",produces = "text/html;charset=UTF-8")
public Object deleteAjaxSplit(HttpServletRequest request){
// 取得第一页的数据
PageInfo info = productInfoService.splitPage(1,PAGE_SIZE);
request.getSession().setAttribute("info",info);
return request.getAttribute("msg");
}
product.jsp
//单个删除
function del(pid) {
if (confirm("确定删除吗")) {
//向服务器提交请求完成删除
<%-- window.location="${pageContext.request.contextPath}/prod/delete.action?pid="+pid;--%>
$.ajax({
url:"${pageContext.request.contextPath}/prod/delete.action",
data:{"pid":pid},
type:"post",
dataType:"text",
success:function (msg) {
alert(msg);
$("#table").load("http://localhost:8080/admin/product.jsp #table");
}
});
}
}
查看数据库中的数据,可以发现数据已经被删掉了
批量删除商品
通过ajax实现全选按钮的功能
在product.jsp页面中添加方法
<%-- 全选复选框功能的实现--%>
function allClick() {
//取得全选复选框的选中未选 中状态
var flag=$("#all").prop("checked");
//将此状态赋值给每个商品列表里的复选框
$("input[name=ck]").each(function () {
this.checked=flag;
// this.checked=ischeck;
});
}
//单击复选框点击改变复选框功能实现
function ckClick() {
//取得所有name=ck的被选中的复选框
var fiveLength=$("input[name=ck]").length;
// var length=$("input[name=ck]:checked").length;
//取得所有name=ck的复选框
var checkedLength = $("input[name=ck]:checked").length;
// var len=$("input[name=ck]").length;
//比较
if(fiveLength == checkedLength){
$("#all").prop("checked",true);
}else
{
$("#all").prop("checked",false);
}
}
批量删除的商品的功能,在ProductInfoMapper.java中实现方法
//批量删除商品的功能
int deleteBatch(String []ids);
productMapper.xml实现数据库的功能
<!--
//批量删除商品的功能
int deleteBatch(String []ids); 1,4,5
-->
<delete id="deleteBatch" >
delete from product_info where p_id in
<foreach collection="array" item="pid" separator="," open="(" close=")">
#{pid}
</foreach>
</delete>
再productInfoService中创建删除商品的业务逻辑
// 批量删除商品的业务逻辑
int deleteBatch(String []ids);
productInfoServiceImpl实现类
//批量删除商品的功能
int deleteBatch(String []ids);
productAction控制层
@ResponseBody
@RequestMapping(value = "/deleteAjaxSplit",produces = "text/html;charset=UTF-8")
public Object deleteAjaxSplit(HttpServletRequest request){
// 取得第一页的数据
PageInfo info = null;
Object vo = request.getSession().getAttribute("deleteProdVo");
if (vo != null){
info = productInfoService.splitPageVo((ProductInfoVo)vo,PAGE_SIZE);
}else {
info = productInfoService.splitPage(1,PAGE_SIZE);
}
request.getSession().setAttribute("info",info);
return request.getAttribute("msg");
}
// 批量删除商品
// pid = "1,4,5" ps[1,4,5]
@RequestMapping("/deleteBatch")
public String deleteBatch(String pids,HttpServletRequest request){
// 将上传上来的字符串截开,形成商品id的字符组
String []ps = pids.split(",");
// try catch 当商品是已经进入订单后,批量删除会出错
try {
int num = productInfoService.deleteBatch(ps);
if (num > 0 ){
request.setAttribute("msg","批量删除成功!!");
}else {
request.setAttribute("msg", "批量删除失败!!");
}
} catch (Exception e) {
request.setAttribute("msg","商品不可以删除!");
}
return "forward:/prod/deleteAjaxSplit.action";
}
在product.jsp页面中添加方法
//批量删除
function deleteBatch() {
//取得所有被选中删除商品的pid,根据长度判断是否有选中的商品
var cks=$("input[name=ck]:checked");
if(cks.length==0){
alert("请选择将要删除的商品!");
}else{
// 有选中的商品,则取出每个选 中商品的ID,拼提交的ID的数据
var str="";
var pid="";
if(confirm("您确定删除"+cks.length+"条商品吗?")){
//拼接ID
$.each(cks,function () {
//进行提交商品id的字符串的拼接
pid=$(this).val(); //22 33
//进行非空判断,避免出错
if(pid!=null)
str += pid+","; //22,33,44
});
// alert(str+"11111111");
//发送请求到服务器端
<%--// window.location="${pageContext.request.contextPath}/prod/deletebatch.action?str="+str;--%>
$.ajax({
url:"${pageContext.request.contextPath}/prod/deleteBatch.action",
data:{"pids":str},
type:"post",
dataType: "text",
success:function (msg){
alert(msg);
// 将页面显示的商品容器重新刷新
$("#table").load("${pageContext.request.contentType}/admin/product.jsp #table");
}
})
}
}
}
未完待续
写到这里感觉太乱了,我把视频看完学完这个项目之后发现后面还需要在原有的代码中做修改和添加部分代码,所以我直接打算把整个项目整合一下再发,这篇文章我也不想删,因为是跟着项目做然后慢慢记录下来的,所以这个就当作我的记事本吧。
现在已经实现的功能有 用户登录,商品列表查询,商品列表分页,商品添加,添加商品可以添加图片,已有商品的编辑修改,单个商品的删除,全选和多选按钮,批量删除
然后还有一个商品的模糊查询和部分功能的强化没有完成。
后面再发一个自己完全做好的,看起来没有这么乱的出来吧