spring frame 事务回滚的测试

本文介绍了一个基于Spring框架的事务管理示例,通过具体代码展示了如何使用Spring的编程式事务管理和TransactionTemplate来处理数据库操作,包括创建订单和更新等级等业务流程。
 我的环境配置
Mysql :server version: 5.0.45-Debian_1ubuntu3.1-log Debian etch distribution
Spring frame: 2.0
jdk 1.6
数据库的配置:
-- MySQL Administrator dump 1.4
--
--
 ------------------------------------------------------
--
 Server version    5.0.45-Debian_1ubuntu3.1-log


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;


--
--
 Create schema SQLMapStudy
--

CREATE DATABASE IF NOT EXISTS SQLMapStudy;
USE SQLMapStudy;

--
--
 Definition of table `SQLMapStudy`.`ORDER`
--

DROP TABLE IF EXISTS `SQLMapStudy`.`ORDER`;
CREATE TABLE  `SQLMapStudy`.`ORDER` (
  `id` 
int(11NOT NULL auto_increment,
  `
levelint(11default '0',
  `name` 
text,
  
PRIMARY KEY  (`id`)
) ENGINE
=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=latin1;

--
--
 Dumping data for table `SQLMapStudy`.`ORDER`
--

/*!40000 ALTER TABLE `ORDER` DISABLE KEYS */;
LOCK TABLES `
ORDER` WRITE;
INSERT INTO `SQLMapStudy`.`ORDERVALUES  (24,5,'233571'),
 (
25,3,'237607'),
 (
26,4,'951320'),
 (
27,4,'3981449'),
 (
28,3,'4201861'),
 (
29,3,'4286204'),
 (
30,4,'4467730'),
 (
31,4,'4577921'),
 (
32,4,'4644267'),
 (
33,4,'4676767'),
 (
34,4,'8718591'),
 (
35,4,'1200488898355'),
 (
36,3,'1200489291189'),
 (
37,3,'1200489506119'),
 (
38,3,'1200490058635'),
 (
41,4,'1200490554236');
UNLOCK TABLES;
/*!40000 ALTER TABLE `ORDER` ENABLE KEYS */;




/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
要注意的问题:ENGINE=InnoDB

数据库映射对象类Order
/*
 * Copyright (C) 2000-2007 Wang Pengcheng <wpc0000@gmail.com>
 * Licensed to the Wang Pengcheng under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The LGPL licenses this file to You under the GNU Lesser General Public
 * Licence, Version 2.0  (the "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 *
 *     
http://www.gnu.org/licenses/lgpl.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 
*/

//Edit 15 Jan 2008
package com.studyspring.ch5;

public class Order {
    
private int id;
    
private int level;
    
private String name;
    
public int getId() {
        
return id;
    }

    
public void setId(int id) {
        
this.id = id;
    }

    
public int getLevel() {
        
return level;
    }

    
public void setLevel(int level) {
        
this.level = level;
    }

    
public String getName() {
        
return name;
    }

    
public void setName(String name) {
        
this.name = name;
    }

    
}

实现RowMapper:
/*
 * Copyright (C) 2000-2007 Wang Pengcheng <wpc0000@gmail.com>
 * Licensed to the Wang Pengcheng under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The LGPL licenses this file to You under the GNU Lesser General Public
 * Licence, Version 2.0  (the "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 *
 *     
http://www.gnu.org/licenses/lgpl.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 
*/

//Edit 15 Jan 2008
package com.studyspring.ch5;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

public class OrderRowMapper implements RowMapper {

    
public Object mapRow(ResultSet rs, int index) throws SQLException {
        Order order 
= new Order();
        order.setId(rs.getInt(
"id"));
        order.setLevel(rs.getInt(
"level"));
        order.setName(rs.getString(
"name"));
        
return order;
    }


}


为了使用和扩展的方便使用了一些接口
package com.studyspring.ch5;

import java.util.List;

public interface IUserDAO {
    
public List<Order> getUserList();
    
public Order makeOrder(String name);
    
public void changelevel(int userid);

}

///////////////////////////////////////////////////////////////////////////
package com.studyspring.ch5;

public interface IUserManager {
    
public boolean processOrder(String name);

}

以上是一些几本的类,下面就是一些和事务有关的具体实现了。
用于DAO的类:
/*
 * Copyright (C) 2000-2007 Wang Pengcheng <wpc0000@gmail.com>
 * Licensed to the Wang Pengcheng under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The LGPL licenses this file to You under the GNU Lesser General Public
 * Licence, Version 2.0  (the "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 *
 *     
http://www.gnu.org/licenses/lgpl.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 
*/

//Edit 15 Jan 2008
package com.studyspring.ch5;

import java.util.List;

import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.jdbc.core.JdbcTemplate;

public class UserDAOImpl implements IUserDAO {
    
    
private String sql;
    
private JdbcTemplate jdbcTemplate;
    

    
public void changelevel(int userid) {
        Object[] param 
= new Object[]{new Integer(userid)};
        sql 
= "update `ORDER` set level=level+1 where id=?";
        jdbcTemplate.update(sql,param);
    }


    
public List<Order> getUserList() {
        
// TODO Auto-generated method stub
        return null;
    }


    
public Order makeOrder(String name) {
        Order order 
= new Order();
        Object[] param 
= new Object[]{new Integer(3),new String(name)};
        sql
="insert into `ORDER`"
            
+"(level,name) value"
            
+"(?,?)";
        
int rowcount = jdbcTemplate.update(sql, param);
        
        
if(rowcount==1){
            sql
="select * from `ORDER`";
            List list 
= jdbcTemplate.query(sql, new OrderRowMapper());
            order 
=(Order)list.get(list.size()-1);
        }

        
throw new DataAccessResourceFailureException(sql);//如果要人为制造异常可以用这种方式抛出以检验回滚机制
                
//个人检测好象是任何异常都可以,这个任意是指:运行时异常还有spring的DataAccessResourceException的子类
        
//return order;
    }


    
public JdbcTemplate getJdbcTemplate() {
        
return jdbcTemplate;
    }


    
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        
this.jdbcTemplate = jdbcTemplate;
    }


}


业务逻辑类:
/*
 * Copyright (C) 2000-2007 Wang Pengcheng <wpc0000@gmail.com>
 * Licensed to the Wang Pengcheng under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The LGPL licenses this file to You under the GNU Lesser General Public
 * Licence, Version 2.0  (the "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 *
 *     
http://www.gnu.org/licenses/lgpl.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 
*/

//Edit 15 Jan 2008
package com.studyspring.ch5;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.studyspring.ch3.Advice4Hello;

public class UserManagerImpl implements IUserManager {
    
private Log log = LogFactory.getLog(Advice4Hello.class);
    
private IUserDAO userDAO;
    
private PlatformTransactionManager manager;

    
public boolean processOrder(String name) {
        DefaultTransactionDefinition td 
= new DefaultTransactionDefinition(
                TransactionDefinition.PROPAGATION_REQUIRED);
        td.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
        td.setTimeout(
500);
        TransactionStatus status 
= manager.getTransaction(td);//记录回滚前状态

        
try{
            Order order 
= userDAO.makeOrder(name);
            userDAO.changelevel(order.getId());
            log.info(
"The order level changing: "+order.getName());
        }
catch (DataAccessException e) {
            manager.rollback(status);
//启动回滚
            log.warn("Order error");
            
throw e;
        }

        manager.commit(status);
//正常结束,写数据库
        return true;
    }


    
public IUserDAO getUserDAO() {
        
return userDAO;
    }


    
public void setUserDAO(IUserDAO userDAO) {
        
this.userDAO = userDAO;
    }


    
public PlatformTransactionManager getManager() {
        
return manager;
    }


    
public void setManager(PlatformTransactionManager manager) {
        
this.manager = manager;
    }


}


xml配置文件:
需要注意的是:
        <property name="defaultAutoCommit">
            
<value>false</value>
        
</property>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation
="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
    
<bean id="dataSource"
        class
="org.apache.commons.dbcp.BasicDataSource"
        destroy-method
="close">

        
<property name="driverClassName">
            
<value>com.mysql.jdbc.Driver</value>
        
</property>

        
<property name="url">
            
<value>jdbc:mysql://localhost:3306/SpringStudy</value>
        
</property>

        
<property name="username">
            
<value>mysql user name</value>
        
</property>

        
<property name="password">
            
<value>mysql password</value>
        
</property>

        
<property name="defaultAutoCommit">
            
<value>false</value>
        
</property>
        
    
</bean>

    
<bean id="jdbcTemplate"
        class
="org.springframework.jdbc.core.JdbcTemplate">
        
<property name="dataSource">
            
<ref local="dataSource"/>
        
</property>
    
</bean>

    
<bean id="transactionManager"
        class
="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        
<property name="dataSource">
            
<ref local="dataSource" />
        
</property>
    
</bean>

    
<bean id="userOimpl" class="com.studyspring.ch5.UserDAOImpl">
        
<property name="jdbcTemplate">
            
<ref local="jdbcTemplate"/>
        
</property>
    
</bean>

    
<bean id="userManager"
        class
="com.studyspring.ch5.UserManagerImpl">

        
<property name="userDAO">
            
<ref local="userOimpl"/>
        
</property>

        
<property name="manager">
            
<ref local="transactionManager"/>
        
</property>
    
</bean>

</beans>

最终的运行程序
package com.studyspring.ch5;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class PogrammaticTrans {

    
/**
     * 
@param args
     
*/

    
public static void main(String[] args) {
        ApplicationContext ctx 
= new FileSystemXmlApplicationContext(
                
"/src/com/studyspring/ch5/configch5.xml");
        IUserManager userManager 
= (IUserManager) ctx.getBean("userManager");
        System.err.print(userManager.processOrder(Long.toString(System.currentTimeMillis())));
    }


}


如果要用TransactionTemplate这要注意异常捕获的位置和层次关系
package com.studyspring.ch5;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import com.studyspring.ch3.Advice4Hello;

public class UserManagerImplWTT implements IUserManager {
    
private Log log = LogFactory.getLog(Advice4Hello.class);
    
private IUserDAO userDAO;
    
private PlatformTransactionManager manager;

    
public boolean processOrder(final String name) {
        TransactionTemplate tt 
= new TransactionTemplate(manager);
        tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
        tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        tt.setTimeout(
500);

        
try {
            tt.execute(
new TransactionCallback() {

                
public Object doInTransaction(TransactionStatus status) {
                    Order order 
= new Order();
                    order 
= userDAO.makeOrder(name);
                    userDAO.changelevel(order.getId());
                    log.info(
"Finish :" + order.getName());
                    
return order;
                }


            }
);
        }
 catch (Exception e) {
                
//添加这个捕获的原因是:一般我们不会将异常抛给系统,而是利用AOP进行统一处理。
               
//如果在 doInTransaction里面捕获则不会回滚。

        }

        
return true;
    }


    
public IUserDAO getUserDAO() {
        
return userDAO;
    }


    
public void setUserDAO(IUserDAO userDAO) {
        
this.userDAO = userDAO;
    }


    
public PlatformTransactionManager getManager() {
        
return manager;
    }


    
public void setManager(PlatformTransactionManager manager) {
        
this.manager = manager;
    }


}


以上运行后会抛出异常,并且数据库id变化,但是没有数据加入。这就是回滚机制的作用。
感谢spring为我们解决了很多。
package com.ncc.service; import com.ncc.dao.UserDao; import com.ncc.entity.UserDto; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserDao userDao; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 链接数据库根据用户名查询用户信息 UserDto user = userDao.getUserByUserName(username); if (user == null) { throw new UsernameNotFoundException("用户不存在"); } // 获取用户的权限 List<String> privilegeList = userDao.findPrivilegeByUserId(user.getId()); String[] privilegeArray = new String[privilegeList.size()]; privilegeList.toArray(privilegeArray); UserDetails userDetails = User.withUsername(user.getUsername()).password(user.getPassword()).authorities(privilegeArray).build(); return userDetails; } } package com.ncc.service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ncc.dao.UserMapper; import com.ncc.entity.UserDto; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class UserServiceImpl extends ServiceImpl<UserMapper, UserDto> implements UserService { @Autowired private UserMapper userMapper; @Autowired private PasswordEncoder passwordEncoder; private final Integer INSERT_SUCCESS = 1; @Override public boolean insert(UserDto userDto) { userDto.setValid(1); userDto.setPassword(passwordEncoder.encode(userDto.getPassword())); return userMapper.insert(userDto) == INSERT_SUCCESS; } } spring: datasource: url: "jdbc:mysql://localhost:3306/springbootdata?\ characterEncoding=utf-8&serverTimezone=Asia/Shanghai" username: root password: root server: servlet: session: timeout: 86400s port: 9999 mybatis-plus: mapper-locations: classpath*:mybatis/*.xml package com.ncc.controller; import com.ncc.entity.UserDto; import com.ncc.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; @Controller public class RegisterController { @Autowired private UserService userService; @PostMapping("/doRegister") public String doRegister(UserDto user) { if (userService.insert(user)) { return "redirect:/loginview"; } return "register"; } } package com.ncc.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import javax.sql.DataSource; @Configuration @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) public class WebSecurityConfig { @Autowired private DataSource dataSource; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception{ httpSecurity.authorizeHttpRequests() .mvcMatchers("/loginview","/css/**","/image/**","/register","doRegister").permitAll() // .mvcMatchers("/book/admin/**").hasRole("ADMIN") .anyRequest().authenticated() //其他所有请求,登录后都可以访问 .and() .formLogin() .loginPage("/loginview") //设置打开网站的第一个页面为登录页面 .loginProcessingUrl("/doLogin") .and() .csrf().disable() //csrf跨站保护 .headers().frameOptions().sameOrigin(); //frame标签使用 return httpSecurity.build(); } } package com.ncc.dao; import com.ncc.entity.Privilege; import com.ncc.entity.UserDto; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import java.util.ArrayList; import java.util.List; @Repository public class UserDao { @Autowired JdbcTemplate jdbcTemplate; // 根据用户名查询用户信息 public UserDto getUserByUserName(String username){ String sql = "SELECT * FROM user WHERE username = ?"; // 链接数据库查询 List<UserDto> list = jdbcTemplate.query(sql,new BeanPropertyRowMapper<>(UserDto.class),username); if(list != null && list.size()==1){ return list.get(0); } return null; } // 根据用户id查询用户权限 public List<String> findPrivilegeByUserId(Integer userId){ String authoritySQL = "SELECT u.username,p.authority FROM user u,priv p,user_priv up " + "WHERE up.user_id = u.id AND up.priv_id = p.id and u.id = ?"; List<Privilege> list = jdbcTemplate.query(authoritySQL,new BeanPropertyRowMapper<>(Privilege.class),userId); List<String> privileges = new ArrayList<>(); list.forEach(p ->privileges.add(p.getAuthority())); return privileges; } } package com.ncc.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ncc.entity.UserDto; import org.apache.ibatis.annotations.Mapper; @Mapper public interface UserMapper extends BaseMapper<UserDto> { }package com.ncc.entity; public class Privilege { private Integer id; private String authority; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getAuthority() { return authority; } public void setAuthority(String authority) { this.authority = authority; } } package com.ncc.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @TableName("user") public class UserDto { @TableId(type = IdType.AUTO) private Integer id; private String username; private String password; private Integer valid; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } 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 getValid() { return valid; } public void setValid(Integer valid) { this.valid = valid; } public UserDto(Integer id, String username, String password, Integer valid) { this.id = id; this.username = username; this.password = password; this.valid = valid; } public UserDto(){} } package com.ncc.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ncc.entity.UserDto; public interface UserService extends IService<UserDto> { boolean insert(UserDto user); }
最新发布
06-08
根据你提供的代码和配置文件,你的项目中存在以下几个问题可能导致注册成功后没有在数据库表中出现,并且登录失败: --- ### 问题分析 1. **`UserMapper.insert` 方法未正确映射到数据库**: - `UserMapper` 接口继承了 `BaseMapper<UserDto>`,但没有自定义的 `insert` 方法实现。 - 如果 MyBatis-Plus 的默认插入逻辑有问题(如字段未映射正确),可能导致数据未插入。 2. **事务管理问题**: - `@Transactional` 注解可能未生效,导致插入操作失败时事务回滚或未提交。 3. **密码加密问题**: - 注册时使用了 `passwordEncoder.encode(userDto.getPassword())` 对密码进行加密。 - 登录时需要对输入的密码进行解密或匹配验证。如果加密方式不一致,可能导致登录失败。 4. **权限问题**: - 在 `UserDetailsServiceImpl` 中,`findPrivilegeByUserId` 方法获取用户权限。 - 如果权限列表为空或不存在,可能导致登录失败。 5. **Spring Security 配置问题**: - `securityFilterChain` 中配置了 `/doLogin` 作为登录处理 URL,但代码中未提供 `/doLogin` 的具体实现。 - 如果登录逻辑未正确处理,可能导致登录失败。 --- ### 解决方案 #### 1. 检查 `UserMapper.insert` 方法 确保 `UserMapper` 的 `insert` 方法正确映射到数据库表。MyBatis-Plus 的默认 `insert` 方法会自动插入实体类的所有字段。如果字段未映射正确,可以手动定义 SQL 语句: ```java @Mapper public interface UserMapper extends BaseMapper<UserDto> { @Insert("INSERT INTO user (username, password, valid) VALUES (#{username}, #{password}, #{valid})") int insert(UserDto userDto); } ``` --- #### 2. 修改 `UserServiceImpl.insert` 方法 在注册时明确设置 `valid` 字段为 1,并捕获可能的异常: ```java @Override public boolean insert(UserDto userDto) { try { userDto.setValid(1); // 设置用户状态为有效 userDto.setPassword(passwordEncoder.encode(userDto.getPassword())); // 加密密码 return userMapper.insert(userDto) == INSERT_SUCCESS; } catch (Exception e) { e.printStackTrace(); // 打印异常信息 return false; // 插入失败 } } ``` --- #### 3. 检查事务管理 确保 `@Transactional` 正常工作。如果事务未提交,可能是以下原因: - 方法未被 Spring 容器管理(如直接 new 出来的对象)。 - 异常未被捕获,导致事务回滚。 可以通过日志确认事务是否生效: ```java @Transactional(rollbackFor = Exception.class) public class UserServiceImpl extends ServiceImpl<UserMapper, UserDto> implements UserService { ... } ``` --- #### 4. 检查密码加密和匹配 确保注册和登录时密码加密方式一致。例如: ```java // 注册时加密密码 userDto.setPassword(passwordEncoder.encode(userDto.getPassword())); // 登录时匹配密码 if (passwordEncoder.matches(rawPassword, encodedPassword)) { // 密码匹配成功 } ``` --- #### 5. 检查权限获取逻辑 确保 `findPrivilegeByUserId` 方法返回正确的权限列表。例如: ```java @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserDto user = userDao.getUserByUserName(username); if (user == null) { throw new UsernameNotFoundException("用户不存在"); } List<String> privilegeList = userDao.findPrivilegeByUserId(user.getId()); String[] privilegeArray = privilegeList.toArray(new String[0]); return User.withUsername(user.getUsername()) .password(user.getPassword()) .authorities(privilegeArray) .build(); } ``` --- #### 6. 实现 `/doLogin` 登录逻辑 确保登录逻辑正确处理用户认证。例如: ```java @PostMapping("/doLogin") public String doLogin(@RequestParam String username, @RequestParam String password, Model model) { try { Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(username, password) ); SecurityContextHolder.getContext().setAuthentication(authentication); return "redirect:/home"; // 跳转到主页 } catch (BadCredentialsException e) { model.addAttribute("error", "用户名或密码错误"); return "login"; // 返回登录页面 } } ``` --- #### 7. 检查数据库字段 确保数据库表 `user` 的字段与 `UserDto` 实体类一致: ```sql CREATE TABLE user ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, valid TINYINT DEFAULT 1 ); ``` --- ### 测试步骤 1. 注册新用户,检查数据库中是否有记录。 2. 使用注册的用户名和密码尝试登录,观察控制台日志。 3. 检查 `UserDetailsServiceImpl` 是否正确加载用户信息。 4. 确保 `/doLogin` 接口正确处理登录请求。 --- ### 示例代码 以下是完整的 `UserServiceImpl` 和 `UserDetailsServiceImpl` 实现: ```java @Service @Transactional public class UserServiceImpl extends ServiceImpl<UserMapper, UserDto> implements UserService { @Autowired private UserMapper userMapper; @Autowired private PasswordEncoder passwordEncoder; private final Integer INSERT_SUCCESS = 1; @Override public boolean insert(UserDto userDto) { try { userDto.setValid(1); userDto.setPassword(passwordEncoder.encode(userDto.getPassword())); return userMapper.insert(userDto) == INSERT_SUCCESS; } catch (Exception e) { e.printStackTrace(); return false; } } } @Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserDao userDao; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserDto user = userDao.getUserByUserName(username); if (user == null) { throw new UsernameNotFoundException("用户不存在"); } List<String> privilegeList = userDao.findPrivilegeByUserId(user.getId()); String[] privilegeArray = privilegeList.toArray(new String[0]); return User.withUsername(user.getUsername()) .password(user.getPassword()) .authorities(privilegeArray) .build(); } } ``` --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值