SpringBoot + 微信小程序1

1 Spring框架搭建

1.1 下载Eclipse的SpringBoot插件

点击菜单栏的Help->Eclipse Marketplace,选中popular页签,安装Spring Tool插件



安装完成后可以在新建向导中看到Spring Boot的目录


1.2 创建项目

通过新建Spring Starter Project创建项目,选择MyBatis与Web组件,可以在生成的pom文件中将mybatis的依赖注释掉。


生成的MyFirstDemoApplication为项目启动入口,通过@SpringBootApplication注解来标识

@SpringBootApplication
public class MyFirstDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyFirstDemoApplication.class, args);
    }
}

创建hello类,@RestController表示该类为controller,其中匹配的路径及方法通过@RequestMapping注解来配置

@RestController
public class hello {
    @RequestMapping(value="/hello", method=RequestMethod.GET )
    public String hello() {
        return "Hello SpringBoot";      
    }
}

右键 Run As->Spring Boot App 启动项目,可以通过http://localhost:8080/hello路径来访问该controller

2 Spring Boot 项目开发

2.1 数据库表及实体类创建

在MySQL中创建表

CREATE TABLE tb_area (
    area_id int(2) NOT NULL auto_increment,
    area_name varchar(200) NOT NULL,
    priority int(2) NOT NULL DEFAULT'0',
    create_time datetime DEFAULT NULL,
    last_edit_time datetime DEFAULT NULL,
    PRIMARY KEY(area_id),
    UNIQUE KEY UK_AREA(area_name)
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

在项目中新建entity包,在下面新建Area实体类,生成set/get方法

public class Area {
    private Integer areaId;
    private String areaName;
    private Integer priority;
    private Date createDate;
    private Date lastEditTime;
    // set / get method
...
}

2.2 相关配置

在pom文件中添加mysql及c3p0数据库连接池的依赖,确认mybatis依赖

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>

在resource下创建mybatis-config.xml文件,配置全局属性

<?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>
        <!-- 使用jdbc的getGeneratedKeys获取数据库自增主键值 -->
        <setting name="useGeneratedKeys" value="true" />
        <!-- 使用列标签替换列别名 默认:true -->
        <setting name="useColumnLabel" value="true" />
        <!-- 开启驼峰命名转换:Table{create_time} -> Entity{createTime} -->
        <setting name="mapUnderscoreToCamelCase" value="true" />
    </settings>
</configuration>

创建config.dao包,在下面创建文件DataSourceConfiguration,@Configuration表示其为配置文件,@MapperScan("com.example.demo.dao")配置了扫描dao的位置,创建一个dataSource的bean,返回连接池的对象实例ComboPooledDataSource

    @Bean(name = "dataSource")
    public ComboPooledDataSource createDataSource() throws PropertyVetoException {
        // 生成datasource实例
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        // 跟配置文件一样设置以下信息
        // 驱动
        dataSource.setDriverClass(jdbcDriver);
        // 数据库连接URL
        dataSource.setJdbcUrl(jdbcUrl);
        // 设置用户名
        dataSource.setUser(jdbcUsername);
        // 设置用户密码
        dataSource.setPassword(jdbcPassword);
        // 配置c3p0连接池的私有属性
        // 连接池最大线程数
        dataSource.setMaxPoolSize(30);
        // 连接池最小线程数
        dataSource.setMinPoolSize(10);
        // 关闭连接后不自动commit
        dataSource.setAutoCommitOnClose(false);
        // 连接超时时间
        dataSource.setCheckoutTimeout(10000);
        // 连接失败重试次数
        dataSource.setAcquireRetryAttempts(2);
        return dataSource;
    }

其中变量在该方法前创建,通过@Value("${jdbc.driver}")引入application.properties文件中的配置内容

    @Value("${jdbc.driver}")
    private String jdbcDriver;
    @Value("${jdbc.url}")
    private String jdbcUrl;
    @Value("${jdbc.username}")
    private String jdbcUsername;
    @Value("${jdbc.password}")
    private String jdbcPassword;

application.properties文件中添加配置信息

#DataSource
#数据库驱动
jdbc.driver=com.mysql.jdbc.Driver
#数据库链接
jdbc.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&useSSL=false
#数据库用户名
jdbc.username=root

创建SessionFactoryConfiguration类,创建sqlSessionFactory bean,为其设置mybatis-config.xml的ConfigLocation,mapper文件的MapperLocations,DataSource,entity包扫描路径TypeAliasesPackage

    @Value("${mybatis_config_file}")
    private static String mybatisConfigFile;
    @Value("${mapper_path}")
    private static String mapperPath;
    // 实体类所在的package
    @Value("${type_alias_package}")
    private String typeAliasPackage;
    @Autowired
    private DataSource dataSource;

    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactoryBean createSqlSessionFactoryBean() throws IOException {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        // 设置mybatis configuration 扫描路径
        sqlSessionFactoryBean.setConfigLocation(new ClassPathResource(mybatisConfigFile));
        // 添加mapper 扫描路径
        PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + mapperPath;
        sqlSessionFactoryBean.setMapperLocations(pathMatchingResourcePatternResolver.getResources(packageSearchPath));
        // 设置dataSource
        sqlSessionFactoryBean.setDataSource(dataSource);
        // 设置typeAlias 包扫描路径
        sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasPackage);
        return sqlSessionFactoryBean;
    }

2.3 DAO

创建interface AreaDao,添加相应方法

public interface AreaDao {
    List<Area> queryArea();
    Area queryAreaById(int areaId);
    int insertArea(Area area);
    int updateArea(Area area);
    int deleteArea(int areaId);
}

在resource文件夹下创建mapper/AreaDao.xml文件,实现AreaDao中的方法

<?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.example.demo.dao.AreaDao">
    <select id="queryArea" resultType="com.example.demo.entity.Area">
        SELECT area_id, area_name, priority, create_time, last_edit_time
        FROM tb_area
        ORDER BY priority DESC
    </select>
    <select id="queryAreaById" resultType="com.example.demo.entity.Area">
        SELECT area_id, area_name, priority, create_time, last_edit_time
        FROM tb_area
        WHERE area_id=#{areaId}
    </select>
    <insert id="insertArea" useGeneratedKeys="true" keyProperty="areaId"
        keyColumn="area_id" parameterType="com.example.demo.entity.Area">
        INSERT INTO
        tb_area(area_name,priority, create_time,last_edit_time)
        VALUES
        (#{areaName},#{priority}, #{createTime},#{lastEditTime})
    </insert>
    <update id="updateArea" parameterType="com.example.demo.entity.Area">
        update tb_area
        <set>
            <if test="areaName != null">area_name=#{areaName},</if>
            <if test="priority != null">priority=#{priority},</if>
            <if test="lastEditTime != null">last_edit_time=#{lastEditTime}</if>
        </set>
        where area_id=#{areaId}
    </update>
    <delete id="deleteArea">
        DELETE FROM tb_area
        WHERE area_id = #{areaId}
    </delete>
</mapper>

创建Unit Test,@RunWith @SpringBootTest表示用springboot的测试框架来运行,@Ignore忽略该方法的测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class AreaDaoTest {
    //通过spring容器注入Dao的实现类
        @Autowired
        private AreaDao areaDao;

        @Test
        @Ignore
        public void testAQueryArea() {
            List<Area> areaList = areaDao.queryArea();
            // 验证预期值和实际值是否相符
            assertEquals(2, areaList.size());
        }

        @Test       
        public void testBInsertArea() {
            //创建一个区域对象
            Area area = new Area();
            area.setAreaName("Test Park");
            area.setCreateTime(new Date());
            area.setPriority(1);
            //将该对象实例添加入库
            int effectedNum = areaDao.insertArea(area);
            //检测影响行数
            assertEquals(1, effectedNum);
            //校验总数是否+1
            List<Area> areaList = areaDao.queryArea();
            assertEquals(3, areaList.size());
        }

        @Test
        @Ignore
        public void testCQueryAreaById() {
            Area area = areaDao.queryAreaById(2);
            assertEquals("East Park", area.getAreaName());
        }

        @Test
        @Ignore
        public void testDUpateArea() {
            List<Area> areaList = areaDao.queryArea();
            for (Area area : areaList) {
                if ("Test Park".equals(area.getAreaName())) {
                    // 对比之前的priority值
                    assertEquals(1, area.getPriority().intValue());
                    area.setPriority(2);
                    int effectedNum = areaDao.updateArea(area);
                    assertEquals(1, effectedNum);
                }
            }
        }

        @Test
        @Ignore
        public void testEDeleteArea() {
            List<Area> areaList = areaDao.queryArea();
            for (Area area : areaList) {
                if ("Test Park".equals(area.getAreaName())) {
                    int effectedNum = areaDao.deleteArea(area.getAreaId());
                    assertEquals(1, effectedNum);
                }
            }
            // 重新获取一次列表,看看总数是否少1
            areaList = areaDao.queryArea();
            assertEquals(2, areaList.size());
        }
}

2.4 Service

创建配置class TransactionManagementConfiguration,通过@Configuration @EnableTransactionManagement注解标识配置,实现TransactionManagementConfigurer方法,传入dataSource

@Configuration
@EnableTransactionManagement
public class TransactionManagementConfiguration implements TransactionManagementConfigurer{ 
    @Autowired
    private DataSource dataSource;
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        // TODO Auto-generated method stub
        return new DataSourceTransactionManager(dataSource);
    }
}

新建interface

public interface AreaService {
    List<Area> getAreaList();
    Area getAreaById(int areaId);
    boolean addArea(Area area);
    boolean modifyArea(Area area);
    boolean deleteArea(int areaId);
}

新建实现类,其中增删改通过@Transactional来进行事务管理

@service
public class AreaServiceImpl implements AreaService {

    @Autowired
    private AreaDao areaDao;

    @Override
    public List<Area> getAreaList() {
        // 返回所有的区域信息
        return areaDao.queryArea();
    }

    @Override
    public Area getAreaById(int areaId) {
        return areaDao.queryAreaById(areaId);
    }

    @Transactional
    @Override
    public boolean addArea(Area area) {
        // 空值判断,主要是判断areaName不为空
        if (area.getAreaName() != null && !"".equals(area.getAreaName())) {
            // 设置默认值
            area.setCreateTime(new Date());
            area.setLastEditTime(new Date());
            try {
                int effectedNum = areaDao.insertArea(area);
                if (effectedNum > 0) {
                    return true;
                } else {
                    throw new RuntimeException("添加区域信息失败!");
                }
            } catch (Exception e) {
                throw new RuntimeException("添加区域信息失败:" + e.toString());
            }
        } else {
            throw new RuntimeException("区域信息不能为空!");
        }
    }

    @Transactional
    @Override
    public boolean modifyArea(Area area) {
        // 空值判断,主要是areaId不为空
        if (area.getAreaId() != null && area.getAreaId() > 0) {
            // 设置默认值
            area.setLastEditTime(new Date());
            try {
                // 更新区域信息
                int effectedNum = areaDao.updateArea(area);
                if (effectedNum > 0) {
                    return true;
                } else {
                    throw new RuntimeException("更新区域信息失败!");
                }
            } catch (Exception e) {
                throw new RuntimeException("更新区域信息失败:" + e.toString());
            }
        } else {
            throw new RuntimeException("区域信息不能为空!");
        }
    }

    @Transactional
    @Override
    public boolean deleteArea(int areaId) {
        if (areaId > 0) {
            try {
                // 删除区域信息
                int effectedNum = areaDao.deleteArea(areaId);
                if (effectedNum > 0) {
                    return true;
                } else {
                    throw new RuntimeException("删除区域信息失败!");
                }
            } catch (Exception e) {
                throw new RuntimeException("删除区域信息失败:" + e.toString());
            }
        } else {
            throw new RuntimeException("区域Id不能为空!");
        }
    }
}

2.5 Controller

添加controller类,类上的@RequestMapping注解是该类所有方法前面要添加的前缀,@RequestBody Area area可以标识方法接受的数据类型为xml或jason

@RestController
@RequestMapping("/superadmin")
public class AreaController {
    @Autowired
    private AreaService areaService;

    @RequestMapping(value = "/listarea", method = RequestMethod.GET)
    private Map<String, Object> listArea() {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        List<Area> list = new ArrayList<Area>();
        // 获取区域列表
        list = areaService.getAreaList();
        modelMap.put("areaList", list);
        return modelMap;
    }

    @RequestMapping(value = "/getareabyid", method = RequestMethod.GET)
    private Map<String, Object> getAreaById(Integer areaId) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 获取区域信息
        Area area = areaService.getAreaById(areaId);
        modelMap.put("area", area);
        return modelMap;
    }

    @RequestMapping(value = "/addarea", method = RequestMethod.POST)
    private Map<String, Object> addArea(@RequestBody Area area)
            throws JsonParseException, JsonMappingException, IOException {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 添加区域信息
        modelMap.put("success", areaService.addArea(area));
        return modelMap;
    }

    @RequestMapping(value = "/modifyarea", method = RequestMethod.POST)
    private Map<String, Object> modifyArea(@RequestBody Area area)
            throws JsonParseException, JsonMappingException, IOException {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 修改区域信息
        modelMap.put("success", areaService.modifyArea(area));
        return modelMap;
    }

    @RequestMapping(value = "/removearea", method = RequestMethod.GET)
    private Map<String, Object> removeArea(Integer areaId) {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        // 修改区域信息
        modelMap.put("success", areaService.deleteArea(areaId));
        return modelMap;
    }

}

运行测试相关url


2.6 统一异常处理

创建异常处理类,@ExceptionHandler(value = Exception.class)指定异常类型,@ResponseBody表示返回在页面的body

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Map<String, Object> exceptionHandler(HttpServletRequest req, Exception e) throws Exception {
        Map<String, Object> modelMap = new HashMap<String, Object>();
        modelMap.put("success", false);
        modelMap.put("errMsg", e.getMessage());
        return modelMap;
    }

}

将service中getAreaById方法添加int a = 1/0;测试异常

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,724评论 6 342
  • Spring 技术笔记Day 1 预热知识一、 基本术语Blob类型,二进制对象Object Graph:对象图...
    OchardBird阅读 961评论 0 2
  • 1 一月的广州,夹杂小雨,也算是有点冬天的感觉。农村出来的晓静,经历了两次高考的洗...
    你们喜爱的panda阅读 232评论 0 0
  • 我2005年上高中,到08年去清华读书,三年时间,那是我对绘画艺术的启蒙时期。期间我遇到过各种各样的老师和同学,从...
    辽兰龙灵阅读 1,532评论 31 30