一、逆向工程
首先通过CodeGenerator基于数据库表生产对应的POJI、Mapper、Service、ServiceImpl、Controller等需要的类。
逆向工程使用了MybatisPlus提供的AutoGenerator,代码可去官网查看。
代码生成器里面包括一些全局配置,可以设置作者、日期等;
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
//作者
gc.setAuthor("roro");
//打开输出目录
gc.setOpen(false);
//xml开启 BaseResultMap
gc.setBaseResultMap(true);
//xml 开启BaseColumnList
gc.setBaseColumnList(true);
//日期格式,采用Date
gc.setDateType(DateType.ONLY_DATE);
mpg.setGlobalConfig(gc);
数据源配置,包括数据源url,驱动、用户名、密码;
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/seckill?
useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia" +
"/Shanghai");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
mpg.setDataSource(dsc);
包配置,要将那些类放在什么包下
// 包配置
PackageConfig pc = new PackageConfig();
pc.setParent("com.example.seckill")
.setEntity("pojo")
.setMapper("mapper")
.setService("service")
.setServiceImpl("service.impl")
.setController("controller");
mpg.setPackageInfo(pc);
自定义配置
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
Map<String,Object> map = new HashMap<>();
map.put("date1","1.0.0");
this.setMap(map);
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化
return projectPath + "/src/main/resources/mapper/" +
tableInfo.getEntityName() + "Mapper"
+ StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig()
.setEntity("templates/entity.java")
.setMapper("templates/mapper.java")
.setService("templates/service.java")
.setServiceImpl("templates/serviceImpl.java")
.setController("templates/controller.java");
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
//数据库表映射到实体的命名策略,驼峰命名法
strategy.setNaming(NamingStrategy.underline_to_camel);
//数据库表字段映射到实体的命名策略
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//lombok模型
strategy.setEntityLombokModel(true);
//生成 @RestController 控制器
// strategy.setRestControllerStyle(true);
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setControllerMappingHyphenStyle(true);
//表前缀
strategy.setTablePrefix("t_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
二、登录功能
1. 准备login界面
url输入:localhost:8080/login/toLogin
进入登录页面;
表单输入用户名、密码,点击登录后调用doLogin()
,跳转至/login/doLogin
进行用户名及密码校验,校验通过则跳转至/goods/toList
,校验失败则提示失败信息。
<script>
function login() {
$("#loginForm").validate({
submitHandler: function (form) {
doLogin();
}
});
}
function doLogin() {
g_showLoading();
var inputPass = $("#password").val();
var salt = g_passsword_salt;
var str = "" + salt.charAt(0) + salt.charAt(2) + inputPass +
salt.charAt(5) + salt.charAt(4);
var password = md5(str);
$.ajax({
url: "/login/doLogin",
type: "POST",
data: {
mobile: $("#mobile").val(),
password: password
},
success: function (data) {
layer.closeAll();
if (data.code == 200) {
layer.msg("成功");
window.location.href="/goods/toList";
} else {
layer.msg(data.message);
}
},
error: function () {
layer.closeAll();
}
});
}
</script>
2. 页面跳转功能实现
@Controller
@RequestMapping("/login")
@Slf4j
public class LoginController {
@Autowired
private IUserService userService;
/**
* 跳转登录页面
* @author 47roro
* @date 2022/4/3
* @param
* @return java.lang.String
**/
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
@RequestMapping("/doLogin")
@ResponseBody
public RespBean doLogin(@Valid LoginVo loginVo, HttpServletRequest request, HttpServletResponse response){
//log.info(loginVo.toString());
return userService.doLogin(loginVo, request, response);
}
}
@Controller
@RequestMapping("/goods")
public class GoodsController {
/**
* 跳转到商品列表页面
* @author 47roro
* @date 2022/4/3
* @param session
* @param model
* @param cookie
* @return java.lang.String
**/
@RequestMapping("/toList")
public String toList(HttpSession session, Model model, @CookieValue("userCookie") String cookie){
if(StringUtils.isEmpty(cookie)){
return "login";
}
User user = (User) session.getAttribute(cookie);
if(null == user){
return "login";
}
model.addAttribute("user", user);
return "goodsList";
}
}
3. 登录服务
/**
* 服务实现类
* @author 47roro
* @since 2022-04-03
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Autowired
private UserMapper userMapper;
/**
* 登录
* @author 47roro
* @date 2022/4/3
* @param loginVo
* @return com.example.seckill.vo.RespBean
**/
@Override
public RespBean doLogin(LoginVo loginVo, HttpServletRequest request, HttpServletResponse response) {
String mobile = loginVo.getMobile();
String password = loginVo.getPassword();
User user = userMapper.selectById(mobile);
// 如果用户名不存在,抛出登录失败信息。
if(null == user){
throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
}
// 如果用户密码错误,抛出登录失败信息。(获取到前端加密后的密码和数据库内保存的加密密码对比)
if(!MD5Util.frompassToDBPass(password, user.getSalt()).equals(user.getPassword())){
throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
}
// 生成cookie
String cookie = UUIDUtil.uuid();
request.getSession().setAttribute(cookie, user);
CookieUtil.setCookie(request, response, "userCookie", cookie);
// 登录成功
return RespBean.success();
}
}
4. 用户名校验
/**
* @author 47roro
* @create 2022/4/3
* @description: 手机号码校验
*/
public class ValidatorUtil {
private static final Pattern mobile_pattern = Pattern.compile("[1]([3-9])[0-9]{9}$");
public static boolean isMobile(String mobile){
if(!StringUtils.hasLength(mobile)){
return false;
}
Matcher matcher = mobile_pattern.matcher(mobile);
return matcher.matches();
}
}
5. 其他
自定义注解,校验手机号:
/**
* @author 47roro
* @create 2022/4/3
* @description: 自定义注解校验手机号
*/
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = {IsMobileValidator.class}
)
public @interface IsMobile {
boolean required() default true;
String message() default "手机号码格式错误";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
全局异常:
/**
* @author 47roro
* @create 2022/4/3
* @description: 全局异常处理类
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public RespBean ExceptionHandler(Exception e) {
if (e instanceof GlobalException) {
GlobalException ex = (GlobalException) e;
return RespBean.error(ex.getRespBeanEnum());
} else if (e instanceof BindException) {
BindException ex = (BindException) e;
RespBean respBean = RespBean.error(RespBeanEnum.BIND_ERROR);
respBean.setMessage("参数校验异常:" + ex.getBindingResult().getAllErrors().get(0).getDefaultMessage());
return respBean;
}
return RespBean.error(RespBeanEnum.ERROR);
}
}
请求枚举类:
/**
* @author 47roro
* @create 2022/4/3
* @description: 请求枚举类
*/
@Getter
@ToString
@AllArgsConstructor
public enum RespBeanEnum {
//通用
SUCCESS(200, "SUCCESS"),
ERROR(500, "服务端异常"),
//登录模块
LOGIN_ERROR(500210, "用户名或密码错误"),
MOBILE_ERROR(500211, "手机号码不正确"),
BIND_ERROR(500212, "参数校验异常");
private final Integer code;
private final String message;
}