阅读量:0
项目实战一
这里实战的是我Javaweb项目实战(后端篇)的改写
Javaweb项目实战用到的技术是servlet+vue3
这里用到的是spring+springmvc+mybatis+vue3
项目结构
步骤一:导入需要依赖
<!--mybatis核心--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.16</version> </dependency> <!--德鲁伊连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.8</version> </dependency> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.32</version> </dependency> <!--简化实体类的getset--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.32</version> </dependency> <!-- 方便使用JdbcTemplate事务也需要它--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>6.0.6</version> </dependency> <!--spring context依赖--> <!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.0.6</version> </dependency> <!--junit5测试--> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.10.2</version> </dependency> <!--spring test依赖快速使用ioc容器--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>6.0.6</version> <scope>test</scope> </dependency> <!--spring aop依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>6.0.6</version> </dependency> <!-- 声明式事务依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>6.0.6</version> </dependency> <!--springmvc依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>6.0.6</version> </dependency> <!--web项目需要servlet--> <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-web-api</artifactId> <version>9.1.0</version> <scope>provided</scope> </dependency> <!--json--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.17.1</version> </dependency> <!-- jsp需要依赖! jstl--> <dependency> <groupId>jakarta.servlet.jsp.jstl</groupId> <artifactId>jakarta.servlet.jsp.jstl-api</artifactId> <version>3.0.0</version> </dependency> <!--整和需要 加载ioc容器--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>6.0.6</version> </dependency> <!--整合需要 spring整合mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.3</version> </dependency> <!--日志--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.5.6</version> </dependency>
步骤二:配置类
2.1 SpringConfig类
package org.example.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.TransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.sql.DataSource; @Configuration @ComponentScan({"org.example.service"}) @EnableAspectJAutoProxy @EnableTransactionManagement public class SpringConfig { //开始事务注解 @Bean public TransactionManager transactionManager(DataSource dataSource){ DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); dataSourceTransactionManager.setDataSource(dataSource); return dataSourceTransactionManager; } }
2.2 JdbcConfig类
package org.example.config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import javax.sql.DataSource; @Configuration @PropertySource({"classpath:jdbc.properties"}) public class JdbcConfig { @Value("${jdbc.driverClassName}") private String driverClassName; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean public DataSource getDataSource(){ DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driverClassName); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } }
2.3 MybatisConfig类
package org.example.config; import com.github.pagehelper.PageInterceptor; import jakarta.servlet.jsp.jstl.core.Config; import org.apache.ibatis.logging.slf4j.Slf4jImpl; import org.apache.ibatis.session.AutoMappingBehavior; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.sql.DataSource; import java.util.Properties; @Configuration public class MybatisConfig { @Bean public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){ SqlSessionFactoryBean sqlSession= new SqlSessionFactoryBean(); sqlSession.setDataSource(dataSource); org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); configuration.setLogImpl(Slf4jImpl.class); //日志 configuration.setMapUnderscoreToCamelCase(true); //驼峰映射 configuration.setAutoMappingBehavior(AutoMappingBehavior.FULL);//自动映射 数据库表和java对象 sqlSession.setConfiguration(configuration); sqlSession.setTypeAliasesPackage("org.example.pojo"); //别名 //分页插件 PageInterceptor pageInterceptor = new PageInterceptor(); Properties properties = new Properties(); properties.setProperty("helperDialect","mysql"); pageInterceptor.setProperties(properties); sqlSession.addPlugins(pageInterceptor); return sqlSession; } @Bean public MapperScannerConfigurer mapperScannerConfigurer(){ MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("org.example.mapper"); return mapperScannerConfigurer; } }
2.4 SpringMvcConfig类
package org.example.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; @Configuration @ComponentScan({"org.example.controller"}) @EnableWebMvc public class SpringMvcConfig implements WebMvcConfigurer { //全局异常处理 @Override public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { } //静态资源 @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } }
2.5 JavaConfig类
package org.example.config; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class JavaConfig extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{JdbcConfig.class, SpringConfig.class, MybatisConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
步骤三:创建日志文件 logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="true"> <!-- 指定日志输出的位置,ConsoleAppender表示输出到控制台 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <!-- 日志输出的格式 --> <!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 --> <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- 设置全局日志级别。日志级别按顺序分别是:TRACE、DEBUG、INFO、WARN、ERROR --> <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 --> <root level="DEBUG"> <!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender --> <appender-ref ref="STDOUT"/> </root> <!-- 根据特殊需求指定局部日志级别,可也是包名或全类名。 --> <logger name="org.example.mapper" level="DEBUG"/> </configuration>
步骤四 创建MD5类,全局统一json类
4.1MD5
package org.example.util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Util { public static String encrypt(String strSrc) { try { char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; byte[] bytes = strSrc.getBytes(); //使用平台的默认字符集将此 String 编码为 byte 序列,并 将结果存储到一个新的 byte 数组中。 MessageDigest md = MessageDigest.getInstance("MD5"); md.update(bytes); bytes = md.digest(); int j = bytes.length; char[] chars = new char[j * 2]; int k = 0; for (int i = 0; i < bytes.length; i++) { byte b = bytes[i]; chars[k++] = hexChars[b >>> 4 & 0xf]; chars[k++] = hexChars[b & 0xf]; } return new String(chars); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); throw new RuntimeException("MD5加密出错"); } } }
4.2json
package org.example.json; //全局统一响应的JSON格式处理类 public class Result <T>{ //因为不确定返回消息是什么类型 ,所以这里声明了<T> // 返回码 private Integer code; // 返回消息 private String message; // 返回数据 private T data; public Result(){} // 返回数据 protected static <T> Result<T> build(T data) { //将data添加进去 Result<T> result = new Result<T>(); if (data != null) result.setData(data); return result; //返回一个result对象 } public static <T> Result<T> build(T body, Integer code, String message) { // Result<T> result = build(body); // 创建一个result对象,并添加data对象 result.setCode(code); result.setMessage(message); return result; } public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) { Result<T> result = build(body); //创建result对象并添加data数据 result.setCode(resultCodeEnum.getCode()); //给响应码添加枚举类中的数据 result.setMessage(resultCodeEnum.getMessage()); //给响应消息添加枚举类中的数据 return result; } /** * 操作成功 * @param data baseCategory1List * @param <T> * @return */ public static<T> Result<T> ok(T data){ //返回一个result对象,这是一个操作成功的数据,如果操作成功就执行它 Result<T> result = build(data); //创建result对象并添加data数据 return build(data, ResultCodeEnum.SUCCESS); //调用上面的方法,将枚举类中的ResultCodeEnum.SUCCESS赋值给响应码和响应消息并返回result } public Result<T> message(String msg){ this.setMessage(msg); return this; } public Result<T> code(Integer code){ this.setCode(code); return this; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
package org.example.json; public enum ResultCodeEnum { SUCCESS(200,"success"), USERNAEM_ERROR(501,"usernameError"), PASSWORD_ERROR(503,"passwordError"), NOTLOGIN(504,"notlogin"), USERNAME_USED(505,"usernameUsed"); private Integer code; private String message; private ResultCodeEnum(Integer code ,String message){ this.code= code; this.message = message; } public Integer getCode() { return code; } public String getMessage() { return message; } }
步骤五:三层架构
mapper层
1.账户表SysUserMapper
public interface SysUserMapper { int add(SysUser sysUser); SysUser findByUsername(String username); }
对应的xml文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- namespace等于mapper接口类的全限定名,这样实现对应 --> <mapper namespace="org.example.mapper.SysUserMapper"> <insert id="add"> insert into sys_user values(default,#{username},#{userPwd}) </insert> <select id="findByUsername" resultType="sysUser"> select * from sys_user where username =#{username} </select> </mapper>
2.数据表SysSchedule
package org.example.mapper; import org.example.pojo.SysSchedule; import java.util.List; public interface SysScheduleMapper { /** * 用于向数据中增加一条日程记录 * @param schedule 日程数据以SysSchedule实体类对象形式入参 * @return 返回影响数据库记录的行数, 行数为0说明增加失败,行数大于0说明增加成功 */ int addSchedule(int uid); /** * 查询所有用户的所有日程 * @return 将所有日程放入一个:List<SysSchedule>集合中返回 */ List<SysSchedule> findAll(); List<SysSchedule> findItemListByUid(int uid); Integer addDefault(int uid); Integer updateSchedule(SysSchedule schedule); Integer removeSchedule(int sid); }
对应的xml文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- namespace等于mapper接口类的全限定名,这样实现对应 --> <mapper namespace="org.example.mapper.SysScheduleMapper"> <insert id="addDefault"> insert into sys_schedule values (DEFAULT,#{uid},'请输入日程',0) </insert> <insert id="addSchedule"> insert into sys_schedule values(DEFAULT,#{uid},#{title},#{completed}) </insert> <update id="updateSchedule"> update sys_schedule set title = #{title} ,completed = #{completed} where sid = #{sid} </update> <delete id="removeSchedule"> delete from sys_schedule where sid = #{sid} </delete> <select id="findItemListByUid" resultType="org.example.pojo.SysSchedule"> select sid ,uid,title,completed from sys_schedule where uid = #{uid} </select> <select id="findAll" resultType="org.example.pojo.SysSchedule"> select * from sys_schedule </select> </mapper>
Service层
1.账户表SysUserMapper
public interface SysUserService { int regist(SysUser sysUser); /** * 根据用户名获得完整用户信息的方法 * @param username 要查询的用户名 * @return 如果找到了返回SysUser对象,找不到返回null */ SysUser findByUsername(String username); }
实现类
@Service public class SysUserServiceImpl implements SysUserService { @Autowired private SysUserMapper sysUserMapper; @Override public int regist(SysUser sysUser) { sysUser.setUserPwd(MD5Util.encrypt(sysUser.getUserPwd())); return sysUserMapper.add(sysUser); } @Override public SysUser findByUsername(String username) { return sysUserMapper.findByUsername(username); } }
2.数据表SysSchedule
public interface SysScheduleService { List<SysSchedule> findItemListByUid(int uid); Integer addDefault(int uid); Integer updateSchedule(SysSchedule schedule); Integer removeSchedul(int sid); }
实现类
@Service public class SysScheduleServiceImpl implements SysScheduleService { @Autowired private SysScheduleMapper sysScheduleMapper; @Override public List<SysSchedule> findItemListByUid(int uid) { return sysScheduleMapper.findItemListByUid(uid); } @Override public Integer addDefault(int uid) { return sysScheduleMapper.addDefault(uid); } @Override public Integer updateSchedule(SysSchedule schedule) { return sysScheduleMapper.updateSchedule(schedule); } @Override public Integer removeSchedul(int sid) { return sysScheduleMapper.removeSchedule(sid); } }
controller层
1.账户表SysUserMapper
@Controller @CrossOrigin @ResponseBody @RequestMapping("user") @Slf4j public class SysUserController { @Autowired private SysUserService service; @RequestMapping("checkUsernameUsed") public Result checkUsernameUsed(String username) { SysUser sysUser = service.findByUsername(username); Result result = Result.ok(null); if (sysUser != null) { result = Result.build(null, ResultCodeEnum.USERNAME_USED); } log.info("用户名是否被占用:{}", result); return result; } @RequestMapping(value = "login",method = RequestMethod.POST) public Result login(@RequestBody SysUser sysUser) { //2 调用服务层方法,根据用户名查询用户信息 SysUser loginUser = service.findByUsername(sysUser.getUsername()); Result result = null; if (null == loginUser) { result = Result.build(null, ResultCodeEnum.USERNAEM_ERROR); } else if (!MD5Util.encrypt(sysUser.getUserPwd()).equals(loginUser.getUserPwd())) { result = Result.build(null, ResultCodeEnum.PASSWORD_ERROR); } else { // 登录程序,将用户uid和username响应给客户端 Map data = new HashMap(); loginUser.setUserPwd(""); data.put("loginUser", loginUser); result = Result.ok(data); } log.info("用户名是否被占用:{}", result); // 3将登录结果响应给客户端 return result; } @RequestMapping("regist") public Result regist(@RequestBody SysUser sysUser){ int regist = service.regist(sysUser); Result result = Result.ok(null); if (regist < 1) { result = Result.build(null, ResultCodeEnum.USERNAME_USED); } log.info("用户注册:{}", result); return result; } @RequestMapping("select") public Result select(String username) { SysUser sysUser = service.findByUsername(username); Result result = Result.ok(null); if (sysUser != null) { result = Result.build(null, ResultCodeEnum.USERNAME_USED); } log.info("用户名是否被占用:{}", result); return result; } }
2.数据表SysSchedule
@Slf4j @CrossOrigin @ResponseBody @Controller @RequestMapping("schedule") public class SysScheduleController { @Autowired private SysScheduleService service; @RequestMapping("removeSchedule") public Result removeSchedule(int sid){ Integer i = service.removeSchedul(sid); if(i<0){ return Result.build(null, ResultCodeEnum.NOTLOGIN); }else { return Result.ok(null); } } @RequestMapping(value = "updateSchedule",method = RequestMethod.POST) public Result updateSchedule(@RequestBody SysSchedule schedule){ Integer i = service.updateSchedule(schedule); if(i<0){ return Result.build(null, ResultCodeEnum.NOTLOGIN); }else { return Result.ok(null); } } @RequestMapping("addDefaultSchedule") public Result addDefaultSchedule(int uid){ Integer i = service.addDefault(uid); if(i<0){ return Result.build(null, ResultCodeEnum.NOTLOGIN); }else { return Result.ok(null); } } @RequestMapping("findAllSchedule") public Result findAllSchedule(int uid){ List<SysSchedule> itemList = service.findItemListByUid(uid); // 将用户的所有日程放入一个Result对象 Map data =new HashMap(); data.put("itemList",itemList); Result result = Result.ok(data); // 将Result对象转换为json响应给客户端 return result; } }
总结
与servlet相比
ssm
简化了响应json的WebUtil
简化了JDBCUtil
简化了全局统一 处理servlet的BaseContoller
简化了跨域CrosFilter的java文件
ssm 使用@CrossOrigin注解就使当前文件可以跨域大大减少了代码量
ssm使用@ResponseBody注解就使响应数据变为json形式
ssm使用@RequestMapping就相当于一个servlet所以无需统一处理servlet