Spring整合SpringMVC与Mybatis(SSM)实现完整登录功能流程详解
作者:天海奈奈 发布时间:2022-07-15 10:19:25
项目演示
演示中只用一个用户登录,只是为了测试功能,实际使用中是根据数据库表内数据来决定的。
1 创建工程完成配置
1 ieda新建maven项目名字随便起
2 点击文件,项目 ,模块 ,点加号添加web模块 ,这里要注意文件路径
我们改一下第一项的路径 从web 改成src\main\webapp
下面Web资源目录也改一下
选择webapp 点击右下角创建工件系统自动创建工件,点确认
发现我们webapp有个小蓝点就算成功了。
这个时候先在java包下建一个test类构建一下项目,看一下target包出来没,如果先配置tomcat target得后期手动拉出来,很麻烦。
现在开始配tomcat 点击右上角添加配置
点击加号选择tomcat本地
点击配置,主目录放我们tomcat的文件夹,系统会自动生成其他的
完成后点右下角的小红灯泡配置工件,进去后不用动,把下面的应用程序上下文改为 “/” 就行。
点击确认。 为了验证配置是否可用进入webapp目录下,新建一个index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<h1> 配置完成,终于可以开始了</h1>
</body>
</html>
点击gebug启动tomcat ,根据之前的端口在浏览器看看有没有我们写的网页
如果网页显示正常我们开始添加依赖和写配置文件。
pom.xml 这里只显示需要加的,每个依赖我也标上了注释
<repositories>
<repository>
<id>aliyun</id>
<name>aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
<dependencies>
<!-- webmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.8</version>
</dependency>
<!-- json序列化-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.12.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
<!-- JDBC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.8</version>
</dependency>
<!-- mybatis-plus 自动引入mybatis-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.4.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!-- druid 连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
<!-- junit单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.8</version>
</dependency>
<!-- javax.servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
<!--只在测试时用-->
</dependency>
<!-- 日志组件-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- MD5加密组件-->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
</dependencies>
在resources下新建applicationContext.xml 来作为配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:tx="http://www.springframework.org/schema/tx"
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/task
http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 组件扫描,完成对象的创建与初始化 base-package写自己的 -->
<context:component-scan base-package="com.xatu"/>
<!-- 开启注解模式-->
<mvc:annotation-driven>
<!-- 消息转换器-->
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<!--设置属性 媒体类型(list集合)-->
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=utf-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 把静态资源排除在外-->
<mvc:default-servlet-handler/>
<!--MyBatis与Spring的整合配置 -->
<!--1.配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- 实例化DruidDataSource设置与连接相关的属性-->
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<!-- jdbc驱动-->
<property name="url" value="jdbc:mysql://localhost:3306/cnpc_comment?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"/>
<!-- URL连接字符串 用户名密码写自己mysql数据库的账号密码-->
<property name="username" value="******"/>
<!-- 用户名-->
<property name="password" value="******"/>
<!-- 密码-->
<property name="initialSize" value="5"/>
<!-- 初始化时几个数据库连接,初始数量-->
<property name="maxActive" value="20"/>
<!-- 最大数量-->
</bean>
<!--2.配置SessionFactoryBean-->
<!--SqlSessionFactoryBean用于根据配置信息创建SqlSessionFactory,不再需要我们自己编码创建-->
<!-- 没有引入mybatis-plus之前的 <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">-->
<bean id="sessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 数据源 ref关联到 上面的dataSource对象-->
<property name="mapperLocations" value="classpath:mappers/*.xml"/>
<!-- 加载对象过程中扫描哪个文件 保存sql文件的xml-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 本身框架配置文件路径-->
<!-- MyBaits Plus 3.4以后版本需要在MybatisSqlSessionFactoryBean.plugins属性中进行设置 -->
<property name="plugins">
<array>
<bean class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor">
<property name="interceptors">
<list>
<bean class="com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor"/>
</list>
</property>
</bean>
</array>
</property>
<!-- 插件配置项 代表一系列插件,
实例化一个MybatisPlusInterceptor插件容器
用interceptors进行指定
-->
</bean>
<!--3.配置Mapper扫描器 value 写自己mapper的位置-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xatu.mapper"/>
</bean>
<!-- 声明式事务配置-->
<!-- 1,定义事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 2,开启注解模式的声明式事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
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>
<!-- MyBatis Plus 3.4版本以前配置分页插件 -->
<!--<plugins>
<plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"></plugin>
</plugins>-->
</configuration>
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--向控制台书写日志的追加器-->
<encoder>
<pattern>%d{HH:mm:ss} %-5level [%thread] %logger{30} - %msg%n</pattern>
<!-- 线程名字,产生日志的时间,日志的级别,由哪个类产生的日志-->
<charset>GBK</charset>
</encoder>
</appender>
<root level="debug">
<!-- 最低允许输出debug级别的日志,日志向控制台进行输出-->
<appender-ref ref="console"/>
</root>
</configuration>
mappers包下的manager.xml 他要跟自己的mapper包进行绑定 由于用的mybatis-plus所以不用自己写语句
<?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.xatu.mapper.">
</map
基本配置就完成了
2 表设计
表名叫manager (实体类要绑定的注意)
3 实体类
@TableName("manager")
public class Manager {
@TableId(type = IdType.AUTO)
private Long managerId;
private String username;
private String password;
private Integer salt;
@Override
public String toString() {
return "Manager{" +
"userId=" + managerId +
", username='" + username + '\'' +
", password='" + password + '\'' +
", salt=" + salt +
'}';
}
public Long getUserId() {
return managerId;
}
public void setUserId(Long userId) {
this.managerId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getSalt() {
return salt;
}
public void setSalt(Integer salt) {
this.salt = salt;
}
}
4 mapper
public interface ManagerMapper extends BaseMapper<Manager> {
}
5 service
public interface ManagerService {
public Manager checkLogin1(String username, String password);
}
Impl 实现类
先使用mapper查看是否用这个用户名的用户再调用用户表的信息来判断密码是否正确,我们这里假设没有重名用户。
@Service
//默认方法不开启事务
@Transactional(propagation = Propagation.NOT_SUPPORTED,readOnly = true)
public class ManagerServiceImpl implements ManagerService {
@Resource
private ManagerMapper managerMapper;
@Transactional(rollbackFor = Exception.class)
@Override
public Manager checkLogin1(String username, String password) {
QueryWrapper<Manager> wrapper = new QueryWrapper();
wrapper.eq("username", username);
Manager manager = managerMapper.selectOne(wrapper);
if (manager == null) {
throw new MemberException("用户不存在");
}
String md5 = MD5Utils.md5Digest(password, manager.getSalt());
if (!md5.equals(manager.getPassword())) {
throw new MemberException("您输入的密码有误");
}
return manager;
}
}
异常
public class MemberException extends RuntimeException{
public MemberException(String message){
super(message);
}
}
6 controller
调用service的chedkLogin1方法来检验登录 为了安全,在成功登录后我们将密码 和盐值 设为null
@RestController
@RequestMapping("/api/manager")
public class ManagerController {
@Resource
private ManagerService managerService;
@PostMapping("/check_login1")
public ResponseUtils checkLogin1(String username , String password){
ResponseUtils resp ;
resp = new ResponseUtils();
try {
Manager manager = managerService.checkLogin1(username, password);
manager.setPassword(null);
manager.setSalt(null);
resp = new ResponseUtils().put("manager" , manager);
}catch (Exception e){
e.printStackTrace();
resp = new ResponseUtils(e.getClass().getSimpleName(), e.getMessage());
}
return resp;
}
}
7 工具类
MD5
用来使用hash算法使密码变复杂
public class MD5Utils {
public static String md5Digest(String source ,Integer salt){
char[] ca = source.toCharArray();
for(int i = 0 ; i < ca.length ;i++){
ca[i] = (char) (ca[i] + salt);
}
String target = new String(ca);
String md5 = DigestUtils.md5Hex(target);
return md5;
}
}
统一返回对象
public class ResponseUtils {
private String code;//服务处处理编码
private String message;//服务器返回消息
private Map data = new LinkedHashMap<>();//服务器返回的数据
//成功
public ResponseUtils(){
this.code = "0";
this.message = "success";
}
//失败,传入编码和消息
public ResponseUtils(String code , String message){
this.code = code;
this.message = message;
}
//给data进行赋值
public ResponseUtils put(String key , Object value){
this.data.put(key, value);
return this;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Map getData() {
return data;
}
public void setData(Map data) {
this.data = data;
}
}
整体
8 前端页面
我们是有vue 并且使用element-plus组件库来简化和美化我们的页面
这里我选择的是创建静态文件包,里面放着常用文工具,需要的时候直接把包放在webapp下载页面编写时进行调用。没有的话请选择替他方法,方法很多。
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
<!-- 引入样式 -->
<link rel="stylesheet" type="text/css" href="assets/element-plus/index.css" rel="external nofollow" >
<!-- 引入组件库 -->
<script src="/assets/vue/vue.global.js"></script>
<script src="/assets/element-plus/index.full.js"></script>
<script src="/assets/axios/axios.js"></script>
<style>
.login-box {
border: 1px solid #DCDFE6;
width: 350px;
margin: 180px auto;
padding: 35px 35px 15px 35px;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
box-shadow: 0 0 25px #909399;
}
.login-title{
text-align: center;
margin: 0 auto 40px auto;
color: #303133;
}
</style>
</head>
<body>
<div id="app">
<el-form ref="loginForm" label-width="80px" :rules="rules" :model="form" class="login-box">
<h2 class="login-title">登录</h2>
<el-form-item label="账号" prop="username">
<el-input type="text" placeholder="请输入账号" v-model="form.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" placeholder="请输入密码" v-model="form.password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" v-on:click="onSubmit('loginForm')" style="width:200px">登录</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" v-on:click="returnBack" style="width:200px">退出</el-button>
</el-form-item>
</el-form>
</div>
<script>
const Main = {
data() {
return {
form: {
username: ''
,password: ''
}
,rules:{
username: [
{required: true,message : '账号不能为空' , trigger:'blur'}
],
password:[
{required: true,message : '密码不能为空' , trigger:'blur'}
]
}
}
}
,methods : {
onSubmit(formName){
const objApp = this;
const form = this.$refs[formName];
form.validate((valid) => {
if(valid){
console.info("表单校验成功,准备提交数据");
const form = this.form;
const $message = this.$message;
const params = new URLSearchParams();
params.append("username", form.username);
params.append("password", form.password);
axios.post("/api/manager/check_login1", params)
.then(function (response) {
console.info(response);
const json = response.data;
if(json.code=="0"){
window.location.href = "/index1.html";
}else{
$message.error({message:json.message, offset: 100});
}
});
}
})
}
,returnBack : function (){
window.location.href = "/index.html";
}
}
};
//初始化Vue,绑定Main中的数据,利用ElementPlus对#app容器进行重新渲染
const app = Vue.createApp(Main);
app.use(ElementPlus);
app.mount("#app");
</script>
</body>
</html>
至于另外两个页面,只是使用a标签添加链接 因为只是登录功能没有下一步所以建立两个网页来判断跳转与登录是否成功
来源:https://blog.csdn.net/weixin_57169969/article/details/126817509


猜你喜欢
- 前言当你编写一个应用时,你通常都会希望用户能够定制化他们和应用交互的方式,以及应用与系统进行交互的方式。这种方式通常被称为 &ldq
- sidebarDepth: 3条件构造器说明以下出现的第一个入参boolean condition表示该条件是否加入最后生成的SQL中,例如
- Sequence序列Sequence 是Kotlin标准库提供的一种容器类型。它和Iterable一样具备对集合进行多步骤操作能力,但是却是
- springboot jpa 延迟加载问题在springboot中,在application.properties的配置文件中新增sprin
- 本文实例为大家分享了Java实现二分查找的变种,供大家参考,具体内容如下普通二分查找:先回顾一下普通的二分查找注意:二分查找有这样一个问题:
- Nacos简介Nacos 英文全称为 Dynamic Naming and Configuration Service,是一个由阿里巴巴团队
- 前言之前一篇文章介绍了基本的统一异常处理思路: Spring MVC/Boot 统一异常处理最佳实践.上篇文章也有许多人提出了一些问题:如何
- 包装类包装类其实就是8种基本数据类型对应的引用类型。基本数据类型引用数据类型byteByteshortShortintIntegerlong
- 前言日常开发中,特别是音视频开发,需要在界面上渲染视频,比如制作一个播放器、或者视频编辑工具、以及视频会议客户端。通常拿到的是像素格式数据,
- 序、前言emmmmm,首先这篇文章讲的不是用BinaryFormatter来进行结构体的二进制转换,说真的BinaryFormatter这个
- Visual Studio 2019 Vue项目 创建成功后可看到如下结构 Visual Studio 2019配置vue项目具体文件结构如
- 常见Bean后处理器的作用:public static void main(String[] args) { &
- 本章是后续学习的基石,只有充分理解了分布式系统的概念和面临的问题,以及ZooKeeper内部的概念,才能懂得ZooKeeper是如何对分布式
- 源代码:http://github.com/lovewenyo/HttpDemo1. HttpURLConnection使用JDK原生提供的
- 概述本文的目的是实现以下的流程:Android/iOS native app 操作摄像头 -> 获取视频流数据 -> 人脸检测或
- 在了解Lambda表达式之前我们先来区分一下面向对象的思想和函数式编程思想的区别面向对象的思想:做一件事情,找一个能解决这个事情的对象,调用
- 前言最近我在项目写了几万行代码,小伙伴担心会让程序启动速度变慢,所以本渣就来做测试。 本渣使用了代码创建器,创建了 1000 个垃圾文件,这
- Spring的出现是为了简化 Java 程序开发,而 SpringBoot 的出现是为了简化 Spring 程序开发.SpringBoot
- 注解的介绍@ControllerAdvice@ControllerAdvice注解是Spring3.2中新增的注解,学名是Controlle
- 对于java开发人员来说,Idea的普及率已经很高了。但是还是很多好用的技巧没有用到,只是用到一些基本的功能,蛮浪费IDEA这个优秀的IDE