-
今天将写好的springboot项目通过本地方式打包发现了这个错误
-
】其实导出这个功能在业务需求中是很多的,今天我就先不重点介绍导出实现过程,主要给大家讲解一下导出文件时候,文件名是中文的情况下会出现乱码、下划线等现象该如何去解决,如何理性分析。涉及知识点:java文件导出,中文名乱码,URLEncoder,java下载乱码,java导出中文名百分号字符串目录问题复现中文名乱码中文名下划线百分号串(ë%S7%.xlsx)中文名正常的模式1、下载异常现象原因1.1 下划线原因1.2 乱码原因1.3 %百分号串原因2、解决乱码方式2.1 源码实现2.2 源码分析Content-disposition应用URLEncoder.encode应用utf-8及ISO-8859-1应用(乱码的祸源)3、彩蛋上皇榜问题复现中文名乱码1、下载异常现象原因1.1 下划线原因没有做任何处理,直接将中文名塞到header里面,错误的代码如下:response.setHeader("Content-disposition","attachment; filename=黄大大的街舞梦.xlsx"); response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("UTF-8");1.2 乱码原因因为错乱使用转义,有些人经常会说用utf-8的ISO-8859-1方式,其实也没有错,但是这个之前应该要做一个encode操作错误代码如下:fileName = new String("黄大大的街舞梦.xlsx".getBytes("utf-8"),"ISO-8859-1"); response.setHeader("Content-disposition","attachment; filename="+ fileName); response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("UTF-8");1.3 %百分号串原因因为后端使用了encode进行中文转码,但是前端下载接收的时候没有用decode进行解码的操作。这个主要是前端的问题。2、解决乱码方式2.1 源码实现其实在上面的1.2就很接近正确的模式了,只是针对中文名缺少一个encode的方式,如下所示正确实现代码如下:fileName = URLEncoder.encode("黄大大的街舞梦.xlsx", "UTF-8"); response.setHeader("Content-disposition","attachment; filename="+ fileName); response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("UTF-8");所以说问题的核心在于没有对中文进行一个URLEncoder.encode的处理,具体效果如一开始效果图。完整实现导出的文章将在下一篇详解。2.2 源码分析可能到这里确实解决了大家的问题,但是呢我们对上面写的东西又了解多少呢?首先是Content-disposition是啥?其次URLEncoder.encode又是啥,还有utf-8及ISO-8859-1又是啥,我们为啥要从这些方向设置入手?下面请听我一一介绍。Content-disposition应用这个是MIME协议的一种扩展,主要目的就是显示待下载的文件,当浏览器接收到请求头后,就会去激活一个下载框,他们的名字需要自己塞值到header里面,从而我们下载的文件名要放这个里面。没有设置它就根本不能触发浏览器下载的那个动作。URLEncoder.encode应用URLEncoder.encode后其中fileName如下所示是带有%字母加数字的组合编码形式,其实这个你就可以这么去理解,后端采用这种编码格式,机器能识别,也能塞到头里面有助于传输,但是切记前端收到的时候用decodeURI进行解密哟,不然下载下来的是é»%之类的乱串。
-
用到了wrapper,ge、le、ne、eq等的用法,及多表查询自写sql整理资料记录一下,以备后续复习。 目录------------(可点击相应目录直接跳转) 一、条件构造器关系介绍 条件构造器关系介绍 : wapper介绍 : 二、项目实例 1、根据主键或者简单的查询条件进行查询 2、MyBatis-Plus还提供了Wrapper条件构造器,具体使用看如下代码: 三、具体使用操作 1、ge、gt、le、lt、isNull、isNotNull 2、eq、ne 3、between、notBetween 4、allEq 5、like、notLike、likeLeft、likeRight 6、in、notIn、inSql、notinSql、exists、notExists 7、or、and 8、嵌套or、嵌套and 9、orderBy、orderByDesc、orderByAsc 10、last 11、指定要查询的列 12、set、setSql 四、项目中实际应用代码实例 实例1--包含 eq相等的比较方法 实例2--包含 ge le ge等比较方法,及分页查询方法 实例3--多表查询,手写sql示例,五表联查 先了解一下内外连接: SQL内连接(INNER JOIN) SQL外连接(OUTER JOIN 一、条件构造器关系介绍 条件构造器关系介绍 : 上图绿色框为抽象类abstract 蓝色框为正常class类,可new对象 黄色箭头指向为父子类关系,箭头指向为父类 wapper介绍 : Wrapper : 条件构造抽象类,最顶端父类 AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件 QueryWrapper : Entity 对象封装操作类,不是用lambda语法 UpdateWrapper : Update 条件封装,用于Entity对象更新操作 AbstractLambdaWrapper : Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column。 LambdaQueryWrapper :看名称也能明白就是用于Lambda语法使用的查询Wrapper LambdaUpdateWrapper : Lambda 更新封装Wrapper 二、项目实例 1、根据主键或者简单的查询条件进行查询 /** * 通过单个ID主键进行查询 */ @Test public void selectById() { User user = userMapper.selectById(1094592041087729666L); System.out.println(user); } /** * 通过多个ID主键查询 */ @Test public void selectByList() { List<Long> longs = Arrays.asList(1094592041087729666L, 1094590409767661570L); List<User> users = userMapper.selectBatchIds(longs); users.forEach(System.out::println); } /** * 通过Map参数进行查询 */ @Test public void selectByMap() { Map<String, Object> params = new HashMap<>(); params.put("name", "张雨琪"); List<User> users = userMapper.selectByMap(params); users.forEach(System.out::println); } 2、MyBatis-Plus还提供了Wrapper条件构造器,具体使用看如下代码: /** * 名字包含雨并且年龄小于40 * <p> * WHERE name LIKE '%雨%' AND age < 40 */ @Test public void selectByWrapperOne() { QueryWrapper<User> wrapper = new QueryWrapper(); wrapper.like("name", "雨").lt("age", 40); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } /** * 名字包含雨 * 年龄大于20小于40 * 邮箱不能为空 * <p> * WHERE name LIKE '%雨%' AND age BETWEEN 20 AND 40 AND email IS NOT NULL */ @Test public void selectByWrapperTwo() { QueryWrapper<User> wrapper = Wrappers.query(); wrapper.like("name", "雨").between("age", 20, 40).isNotNull("email"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } /** * 名字为王性 * 或者年龄大于等于25 * 按照年龄降序排序,年龄相同按照id升序排序 * <p> * WHERE name LIKE '王%' OR age >= 25 ORDER BY age DESC , id ASC */ @Test public void selectByWrapperThree() { QueryWrapper<User> wrapper = Wrappers.query(); wrapper.likeRight("name", "王").or() .ge("age", 25).orderByDesc("age").orderByAsc("id"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } /** * 查询创建时间为2019年2月14 * 并且上级领导姓王 * <p> * WHERE date_format(create_time,'%Y-%m-%d') = '2019-02-14' AND manager_id IN (select id from user where name like '王%') */ @Test public void selectByWrapperFour() { QueryWrapper<User> wrapper = Wrappers.query(); wrapper.appl("date_format(create_time,'%Y-%m-%d') = {0}", "2019-02-14") .inSql("manager_id", "select id from user where name like '王%'"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } /** * 查询王姓 * 并且年龄小于40或者邮箱不为空 * <p> * WHERE name LIKE '王%' AND ( age < 40 OR email IS NOT NULL ) */ @Test public void selectByWrapperFive() { QueryWrapper<User> wrapper = Wrappers.query(); wrapper.likeRight("name", "王").and(qw -> qw.lt("age", 40).or().isNotNull("email")); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } /** * 查询王姓 * 并且年龄大于20 、年龄小于40、邮箱不能为空 * <p> * WHERE name LIKE ? OR ( age BETWEEN ? AND ? AND email IS NOT NULL ) */ @Test public void selectByWrapperSix() { QueryWrapper<User> wrapper = Wrappers.query(); wrapper.likeRight("name", "王").or( qw -> qw.between("age", 20, 40).isNotNull("email") ); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } /** * (年龄小于40或者邮箱不为空) 并且名字姓王 * WHERE ( age < 40 OR email IS NOT NULL ) AND name LIKE '王%' */ @Test public void selectByWrapperSeven() { QueryWrapper<User> wrapper = Wrappers.query(); wrapper.nested(qw -> qw.lt("age", 40).or().isNotNull("email")) .likeRight("name", "王"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } /** * 查询年龄为30、31、32 * WHERE age IN (?,?,?) */ @Test public void selectByWrapperEight() { QueryWrapper<User> wrapper = Wrappers.query(); wrapper.in("age", Arrays.asList(30, 31, 32)); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } /** * 查询一条数据 * limit 1 */ @Test public void selectByWrapperNine() { QueryWrapper<User> wrapper = Wrappers.query(); wrapper.in("age", Arrays.asList(30, 31, 32)).last("limit 1"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } 三、具体使用操作 注意:以下条件构造器的方法入参中的 column 均表示数据库字段 1、ge、gt、le、lt、isNull、isNotNull @Test public void testDelete() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper .isNull("name") .ge("age", 12) .isNotNull("email"); int result = userMapper.delete(queryWrapper); System.out.println("delete return count = " + result); } SQL:UPDATE user SET deleted=1 WHERE deleted=0 AND name IS NULL AND age >= ? AND email IS NOT NULL 2、eq、ne 注意:seletOne返回的是一条实体记录,当出现多条时会报错 @Test public void testSelectOne() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("name", "Tom"); User user = userMapper.selectOne(queryWrapper); System.out.println(user); } 3、between、notBetween 包含大小边界 @Test public void testSelectCount() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.between("age", 20, 30); Integer count = userMapper.selectCount(queryWrapper); System.out.println(count); } SELECT COUNT(1) FROM user WHERE deleted=0 AND age BETWEEN ? AND ? 4、allEq @Test public void testSelectList() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); Map<String, Object> map = new HashMap<>(); map.put("id", 2); map.put("name", "Jack"); map.put("age", 20);9 queryWrapper.allEq(map); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 AND name = ? AND id = ? AND age = ? 5、like、notLike、likeLeft、likeRight selectMaps返回Map集合列表 @Test public void testSelectMaps() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper .notLike("name", "e") .likeRight("email", "t"); List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);//返回值是Map列表 maps.forEach(System.out::println); } SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 AND name NOT LIKE ? AND email LIKE ? 6、in、notIn、inSql、notinSql、exists、notExists in、notIn: notIn("age",{1,2,3})--->age not in (1,2,3) notIn("age", 1, 2, 3)--->age not in (1,2,3) inSql、notinSql:可以实现子查询 例: inSql("age", "1,2,3,4,5,6")--->age in (1,2,3,4,5,6) 例: inSql("id", "select id from table where id < 3")--->id in (select id from table where id < 3) @Test public void testSelectObjs() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //queryWrapper.in("id", 1, 2, 3); queryWrapper.inSql("id", "select id from user where id < 3"); List<Object> objects = userMapper.selectObjs(queryWrapper);//返回值是Object列表 objects.forEach(System.out::println); } SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 AND id IN (select id from user where id < 3) 7、or、and 注意:这里使用的是 UpdateWrapper 不调用or则默认为使用 and 连 @Test public void testUpdate1() { //修改值 User user = new User(); user.setAge(99); user.setName("Andy"); //修改条件 UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>(); userUpdateWrapper .like("name", "h") .or() .between("age", 20, 30); int result = userMapper.update(user, userUpdateWrapper); System.out.println(result); } UPDATE user SET name=?, age=?, update_time=? WHERE deleted=0 AND name LIKE ? OR age BETWEEN ? AND ? 8、嵌套or、嵌套and 这里使用了lambda表达式,or中的表达式最后翻译成sql时会被加上圆括号 @Test public void testUpdate2() { //修改值 User user = new User(); user.setAge(99); user.setName("Andy"); //修改条件 UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>(); userUpdateWrapper .like("name", "h") .or(i -> i.eq("name", "李白").ne("age", 20)); int result = userMapper.update(user, userUpdateWrapper); System.out.println(result); } UPDATE user SET name=?, age=?, update_time=? WHERE deleted=0 AND name LIKE ? OR ( name = ? AND age <> ? ) 9、orderBy、orderByDesc、orderByAsc @Test public void testSelectListOrderBy() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.orderByDesc("id"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 ORDER BY id DESC 10、last 直接拼接到 sql 的最后 注意:只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用 @Test public void testSelectListLast() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.last("limit 1"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } SELECT id,name,age,email,create_time,update_time,deleted,version FROM user WHERE deleted=0 limit 1 11、指定要查询的列 @Test public void testSelectListColumn() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.select("id", "name", "age"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } SELECT id,name,age FROM user WHERE deleted=0 12、set、setSql 最终的sql会合并 user.setAge(),以及 userUpdateWrapper.set() 和 setSql() 中 的字段 @Test public void testUpdateSet() { //修改值 User user = new User(); user.setAge(99); //修改条件 UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>(); userUpdateWrapper .like("name", "h") .set("name", "老李头")//除了可以查询还可以使用set设置修改的字段 .setSql(" email = '123@qq.com'");//可以有子查询 int result = userMapper.update(user, userUpdateWrapper); } UPDATE user SET age=?, update_time=?, name=?, email = '123@qq.com' WHERE deleted=0 AND name LIKE ? 四、项目中实际应用代码实例 (此部分更新于2022年7月20日) 实例1--包含 eq相等的比较方法 实例2--包含 ge le ge等比较方法,及分页查询方法 实例3--多表查询,手写sql示例,五表联查 先了解一下内外连接: 什么是连接表? 多表查询原理:将多个表通过笛卡尔积形成一个虚表,再根据查询条件筛选符合条件的数据。 在关系数据库中,数据分布在多个逻辑表中。 要获得完整有意义的数据集,需要使用连接来查询这些表 中的数据。 SQL Server支持多种 连接包括 INNER JOIN:内连接,关键字在表中存在至少一个匹配时返回行。 left join : 左连接,返回左表中所有的记录以及右表中连接字段相等的记录。 right join : 右连接,返回右表中所有的记录以及左表中连接字段相等的记录。 inner join : 内连接,又叫等值连接,只返回两个表中连接字段相等的行。 full join : 外连接,返回两个表中的行:left join + right join。 cross join : 结果是笛卡尔积,就是第一个表的行数乘以第二个表的行数。 GROUP BY:全外连接, 子句必须放在 WHERE 子句中的条件之后,必须放在 ORDER BY 子句之前 每种连接类型指定SQL Server如何使用一个表中的数据来选择另一个表中的行 SQL内连接(INNER JOIN) 返回两张表中符合连接条件的数据行 内连接是从结果表中删除与被连接表中未匹配行的所有行,所以内连接可能会丢失信息 SQL外连接(OUTER JOIN) 外连接(OUTER JOIN)分 为左连接、右连接和全连接 左连接:返回左表中的所以行,如果左表中行在右表中没有匹配行,则结果中右表中的列返回空值NULL 语法:SELECT * FROM 表1 LEFT OUTER JOIN 表2 ON 条件 eg:我们左连接Student表、Score表查询学生的成绩,SQL 语句如下: SELECT * FROM Student LEFT OUTER JOIN Score ON Student.id = Score.studentID 右 连 接:返回右表中的所以行,如果右表中行在左表中没有匹配行,则结果中左表中的列返回空值NULL 语法:SELECT * FROM 表1 RIGHT OUTER JOIN 表2 ON 条件 eg:我们右连接Student表、Score表查询学生的成绩,SQL 语句如下: SELECT * FROM Student RIGHT OUTER JOIN Score ON Student.id = Score.studentID 全连接:返回左表和右表中的所有行,当某行在另一表中没有匹配行,则另一表中的补NULL 这个是mybatis-plus插件中mapper的一个表查询写法,由多个表内连接或外连接组成的数据。 用到的表结构如下: 分别为问题库表、数据字典、数据字典类型、部门表、用户表 数据示例如下:obdis_problem表里去查type字段内容并返回对应的汉字语义 查询每个字段都进行一次表连接,拿到对应的值,得出一个表结果值,即A\B\C\D等等结果,最后拼起来返回前端展示即可。搞懂了这个,所有的多表查询就基本迎刃而解。 <!-- 问题库列表返回与查询--> <select id="searchMoreProblem" resultType="com.hollysys.obdis.vo.problem.SearchObdisProblem"> select p.id , p.level, A.dict_value as level_text, p.dept_id_mgr, B.org_name as deptIdMgr_text, p.dept_id_work, C.org_name as deptIdWork_text, p.station, D.dict_value as station_text, p.source, E.dict_value as source_text, p.categroy, F.dict_value as categroy_text, p.type, G.dict_value as type_text, p.dev_code, H.dict_value as devCode_text, p.check_time, p.check_user, I.username as checkUser_text, p.deadline, p.deadline_real, p.duty_user, J.username as dutyUser_text, p.correct_user, K.username as correctUser_text, p.state, p.problem, p.requirement, p.solution from obdis_problem p left join t_dict A on p.level = A.id left join t_dept B on p.dept_id_mgr = B.org_id left join t_dept C on p.dept_id_work = C.org_id left join t_dict D on p.station = D.id left join t_dict E on p.source = E.id left join t_dict F on p.categroy = F.id left join t_dict G on p.type = G.id left join t_dict H on p.dev_code = H.id left join t_user I on p.check_user = I.user_id left join t_user J on p.duty_user = J.user_id left join t_user K on p.correct_user = K.user_id where 1=1 <if test="searchObdisProblem.levelText != null and searchObdisProblem.levelText != ''"> and A.dict_value like concat('%', #{searchObdisProblem.levelText}, '%') </if> <if test="searchObdisProblem.deptIdMgrText != null and searchObdisProblem.deptIdMgrText != ''"> and B.org_name like concat('%', #{searchObdisProblem.deptIdMgrText}, '%') </if> <if test="searchObdisProblem.deptIdWorkText != null and searchObdisProblem.deptIdWorkText != '' "> and C.org_name like concat('%', #{searchObdisProblem.deptIdWorkText}, '%') </if> <if test="searchObdisProblem.stationText != null and searchObdisProblem.stationText != ''"> and D.dict_value = #{searchObdisProblem.stationText} </if> <if test="searchObdisProblem.sourceText != null and searchObdisProblem.sourceText != ''"> and E.dict_value = #{searchObdisProblem.sourceText} </if> <if test="searchObdisProblem.categroyText != null and searchObdisProblem.categroyText != ''"> and F.dict_value = #{searchObdisProblem.categroyText} </if> <if test="searchObdisProblem.typeText != null and searchObdisProblem.typeText != ''"> and G.dict_value = #{searchObdisProblem.typeText} </if> <if test="searchObdisProblem.devCodeText != null and searchObdisProblem.devCodeText != ''"> and H.dict_value = #{searchObdisProblem.devCodeText} </if> <if test="searchObdisProblem.checkTimeStart != null "> and p.check_time >= #{searchObdisProblem.checkTimeStart} </if> <if test="searchObdisProblem.checkTimeEnd != null "> and p.check_time <= #{searchObdisProblem.checkTimeEnd} order by p.check_time </if> <if test="searchObdisProblem.checkUserText != null and searchObdisProblem.checkUserText != ''"> and I.username = #{searchObdisProblem.checkUserText} </if> <if test="searchObdisProblem.deadline != null "> and p.deadline = #{searchObdisProblem.deadline} </if> <if test="searchObdisProblem.deadlineReal != null "> and p.deadline_real = #{searchObdisProblem.deadlineReal} </if> <if test="searchObdisProblem.dutyUserText != null and searchObdisProblem.dutyUserText != ''"> and J.username = #{searchObdisProblem.dutyUserText} </if> <if test="searchObdisProblem.correctUserText != null and searchObdisProblem.correctUserText != ''"> and K.username = #{searchObdisProblem.correctUserText} </if> <if test="searchObdisProblem.state != null and searchObdisProblem.state != ''"> and state = #{searchObdisProblem.state} </if> <if test="searchObdisProblem.problem != null and searchObdisProblem.problem != ''"> and p.problem like concat('%', #{searchObdisProblem.problem}, '%') </if> <if test="searchObdisProblem.requirement != null and searchObdisProblem.requirement != ''"> and p.requirement like concat('%', #{searchObdisProblem.requirement}, '%') </if> <if test="searchObdisProblem.solution != null and searchObdisProblem.solution != ''"> and p.solution like concat('%', #{searchObdisProblem.solution}, '%') </if> </select> -------------------------------------------------------------------------------------以下无正文------------------- 参考文档 1、(五)springboot + mybatis plus强大的条件构造器queryWrapper、updateWrapper_青蛙与大鹅的博客-CSDN博客_querywrapper.eq 2、https://blog.csdn.net/kepengs/article/details/112345870 3、Wrapper使用_weixin_39615889的博客-CSDN博客_wrapper使用 4、MyBatis-Plus Wrapper条件构造器查询大全_IT贱男的博客-CSDN博客_wrapper.like 5、https://blog.csdn.net/qq_48209375/article/details/114446611 6、https://blog.csdn.net/TBDBTUO/article/details/123550498 ———————————————— 原文链接:https://blog.csdn.net/qq_39715000/article/details/120090033
-
一、JdbcTemplate(概念和准备) 1 、什么是 JdbcTemplate(Template译为模板) ( 1 ) Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作 2 、准备工作 ( 1 )引入相关 jar 包 ( 2 )在 spring 配置文件配置数据库连接池 com.alibaba.druid.pool.DruidDataSource和com.mysql.jdbc.Driver 都是引入的jar包内的类,不需要自己创建 ( 3 )配置 JdbcTemplate 对象,注入 DataSource(即数据库、数据源) JdbcTemplate是jar包里的类,不是自己创建的。 JdbcTemplate中有个属性叫:dataSource,源码中已经为其设置了set方法,所以用的是set方法注入属性 JdbcTemplate的属性dataSource注入的正是上面数据库连接池对象,等于说把JdbcTemplate对象和数据库连接起来了 (4 )使用注解来创建对象和注入属性,所以需要开启组件扫描 完整的xml: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 数据库连接池 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="jdbc:mysql:///user_db" /><!--对应SQLyog里的数据库--> <property name="username" value="root" /> <!-- 用户名 --> <property name="password" value="4.233928" /> <!-- 密码 --> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> </bean> <!-- JdbcTemplate对象 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--注入dataSource属性--> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 组件扫描 --> <context:component-scan base-package="JDBC"></context:component-scan> </beans> 二、JdbcTemplate 操作数据库(添加) 需求:在表Book中添加一行数据(下图是已经添加完的) 1、对应数据库创建实体类(三个属性对应表Book的三个参数) package JDBC; public class Book { private String userid; private String username; private String ustatus; public String getUserid() { return userid; } public String getUsername() { return username; } public String getUstatus() { return ustatus; } public void setUserid(String userid) { this.userid = userid; } public void setUsername(String username) { this.username = username; } public void setUstatus(String ustatus) { this.ustatus = ustatus; } } 2、接口BookDao,定义增删查改方法 package JDBC; public interface BookDao { //添加(增) public void add(Book book); } 3、接口BookDao的实现类:BookDaoImp 重写add(Book book)方法,向数据库的表中添加数据 JdbcTemplate是jar包org.springframework.jdbc.core中的,添加注解@Autowired后,已经自动注入到JdbcTemplate jdbcTemplate中了。 package JDBC; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class BookDaoImp implements BookDao{ //按类型、自动注入了JdbcTemplate对象(jdbcTemplate即已经是有实体的对象了) //JdbcTemplate对象对象里有增删查改的方法,用来操作数据库 @Autowired private JdbcTemplate jdbcTemplate; @Override public void add(Book book) { //创建添加的sql语句 String addsql = "insert into Book values(?,?,?)"; //调用jdbcTemplate.update实现添加,book.getUserid()、book.getUsername()、book.getUstatus()对应values(?,?,?)里的三个问号 Object[] args = {book.getUserid(), book.getUsername(), book.getUstatus()}; int update = jdbcTemplate.update(addsql,args); //返回值update代表添加了几行 System.out.println(update);//1 } }4、BookService类4、BookService类5 package JDBC; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class BookService { //BookDaoImp类上添加了注解@Repository,即已经生成了他的对象 //按类型、自动注入了BookDaoImp的对象 @Autowired private BookDao bookDao; public void addBook(Book book){ bookDao.add(book); } } 5、测试 :获取BookService类的对象bookService,调用addBook(book)。 package JDBC; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class JDBCTest { @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean7.xml"); BookService bookService = context.getBean("bookService", BookService.class); Book book = new Book(); book.setUserid("1"); book.setUsername("java"); book.setUstatus("active"); bookService.addBook(book); } } ——一般这些是从网页上获得的,这里我们手动输入 最终效果: 三、JdbcTemplate 操作数据库(删、改)——只需修改以下几个文件 package JDBC; public interface BookDao { //添加(增) public void add(Book book); //修改 public void update(Book book); //删除(根据id删除) public void delete(String id); } package JDBC; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class BookDaoImp implements BookDao{ //按类型、自动注入了JdbcTemplate对象 @Autowired private JdbcTemplate jdbcTemplate; @Override public void add(Book book) { //创建添加的sql语句 String addsql = "insert into Book values(?,?,?)"; //调用jdbcTemplate.update实现添加,book.getUserid()、book.getUsername()、book.getUstatus()对应values(?,?,?)里的三个问号 Object[] args = {book.getUserid(), book.getUsername(), book.getUstatus()}; int update = jdbcTemplate.update(addsql,args); //返回值update代表添加了几行 System.out.println(update); } @Override public void update(Book book) { //根据id修改username ustatus String updatesql = "update Book set username=?,ustatus=?where user_id=?"; Object[] args = {book.getUsername(), book.getUstatus(),book.getUserid(),};//注意参数顺序 int update = jdbcTemplate.update(updatesql,args); } @Override public void delete(String id) { //根据user_id删除 String deletesql = "delete from Book where user_id=?"; int update = jdbcTemplate.update(deletesql,id); } } package JDBC; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class BookService { //按类型、自动注入了BookDaoImp的对象 @Autowired private BookDao bookDao; public void addBook(Book book){ bookDao.add(book); } public void update(Book book){ bookDao.update(book); } public void delete(String id){ bookDao.delete(id); } } 四、JdbcTemplate 查询操作 1、查询返回的是某个值 2、查询返回的是某个对象 3、查询返回的是某个集合 ———————————————— 原文链接:https://blog.csdn.net/qq_40643699/article/details/115582536
-
Java中时间与时间戳的转换 1. 时间转换成时间戳 方式一: /** * 时间转换成时间戳,参数和返回值都是字符串 * @param s * @return res * @throws ParseException */ public static String dateToStamp(String s) throws ParseException { String res; //设置时间模版 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = simpleDateFormat.parse(s); long ts = date.getTime(); res = String.valueOf(ts); return res; } 在主函数中设置参数与运行结果 String date=dateToStamp("2021-09-07 09:09:39"); System.out.println(date); //结果:1630976979000 方式二: /** * 日期转换成时间戳,参数可以是日期,返回值是字符串 */ public static void Date2TimeStamp() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String format = sdf.format(new Date()); try { String valueOf = String.valueOf(sdf.parse(format).getTime() / 1000); System.err.println(valueOf); } catch (ParseException e) { e.printStackTrace(); } } 2. 时间戳转换成时间 方式一: /** * 将时间戳转换为时间,参数和返回值都是字符串 * @param s * @return res */ public static String stampToDate(String s){ String res; SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); long lt = new Long(s); Date date = new Date(lt); res = simpleDateFormat.format(date); return res; } 在主函数中设置参数与运行结果 String s="1630339200000"; String date=stampToDate(s); System.out.println(date); //2021-08-31 00:00:00 方式二: /** * 时间戳先转换成日期字符串再转换成日期类型,参数是字符串,返回值是字符串也可是日期 */ public static void TimeStamp2Date() { String timestampString = "1631008034"; String formats = "yyyy-MM-dd HH:mm:ss"; Long timestamp = Long.parseLong(timestampString) * 1000; //日期格式字符串 String dateStr = new SimpleDateFormat(formats, Locale.CHINA).format(new Date(timestamp)); System.err.println(dateStr); Date date = null; SimpleDateFormat formater = new SimpleDateFormat(); formater.applPattern("yyyy-MM-dd HH:mm:ss"); try { date = formater.parse(dateStr); System.err.println(date); } catch (ParseException e) { e.printStackTrace(); } } ———————————————— 原文链接:https://blog.csdn.net/qq_35297368/article/details/120162984
-
问题描述: springboot启动报jar包扫描错误,但不影响项目正常使用: Failed to scan [file:/Users/ds/.m2/repository/com/sun/xml/bind/jaxb-impl/2.2.11/jaxb-core.jar] from classloader hierarchy java.io.FileNotFoundException: /Users/ds/.m2/repository/com/sun/xml/bind/jaxb-impl/2.2.11/jaxb-core.jar (No such file or directory) 原因分析:高版本的tomcat除了加载maven管理的jar包外,还会对jar包中的manifest.mf文件进行分析,加载manifest.mf文件中classpath定义的jar包。 例如:com.sun.xml.bind.jaxb-impl-2.2.11.jar包的MANIFEST.MF文件中Class-Path有jaxb-core.jar,但是该jar包没有定义版本号和路径,导致tomcat从jaxb-impl-2.2.11.jar的路径加载jaxb-core.jar,从而找不到jaxb-core.jar出现Failed to scan的异常。但其实这个jar包已经在其它地方引用了。 解决方案: 方案一: 降低tomcat版本到8.5.0或以下,高版本tomcat会对jar包中的manifest.mf文件进行分析。 方案二: 在启动类中配置不扫描manifest文件 ———————————————— 版权声明:本文为CSDN博主「ds_trojan」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_27990381/article/details/110042215 /** * 不扫描Manifest文件 * @return */ @Bean public TomcatServletWebServerFactory tomcatFactory() { return new TomcatServletWebServerFactory() { @Override protected void postProcessContext(Context context) { ((StandardJarScanner) context.getJarScanner()).setScanManifest(false); } }; }———————————————— 原文链接:https://blog.csdn.net/qq_27990381/article/details/110042215
-
大家在实际项目中想必遇到依赖冲突是特别的头疼,如果项目比较复杂,比较大的话,那依赖冲突解决起来是特别耗费时间和精力的。 这几天在项目里加了个从阿里云OSS中下载文件的接口,其中用到了OSSClientBuilder这个方法,不过由于之前项目中集成的OSS版本太低,没有这个方法,所以需要更新版本,但是更新过版本后却报了依赖冲突的问题。还好用了IDEA中的这个插件,很快就搞定了! 一、插件下载 使用的插件叫做 Maven Helper ,大家可以根据下图的步骤去下载,下载后不用重启idea也是可以使用的。 二、解决冲突 在安装好这个插件后,打开自己的pom.xml文件,大家可以在文件右下角看到 Dependency Analyzer这个模块,点击进去 Conflicts:展示所有冲突。 All Dependencies as List:以列表的方式展示所有依赖。 All Dependencies as Tree:以树形的方式展示所有依赖。 我们选择 aliyun-java-sdk-core,选择以树形展示所有依赖,得到如下的信息显示。 从上图中我们就可以很清楚的看到 aliyun 的包和 spring-clould-starter-alicloud-ans 的包起了冲突,所以我们右键可以看到红框圈出来的 jump to Source 或者直接F4键可以直接跳到 pom.xml 文件中引用该依赖的地方,然后使用 Exclude 标签排除冲突依赖包的引用就可以完美的解决了。 再次启动项目,测试接口发现功能正常了,整个排查过程也就结束了,IDEA的功能还是很强大的。 总结 很多时候的 jar 包冲突,有些是我们很容易排除,例如在pom.xml 中我们就可以发现一些重复引入,但是版本不相同的依赖。还有一些是其他依赖传递依赖进来的,我们在 pom.xml 文件中不能很直观的发现,这时候我们借助工具可以发现这种冲突的依赖。 类似的依赖冲突基本都可以参考上述的方式进行排查,希望通过本篇文章对大家解决项目中依赖冲突有所帮助。 ———————————————— 原文链接:https://blog.csdn.net/Lu_Dai_Ma/article/details/121808103
-
关于安装多个JDK和切换版本 前言 JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。而我们在开发的过程中,也许会需要不同版本的JDK来进行开发工作,那么如何安装多个JDK并随时切换版本呢,本文中将进行详细阐述。 一、下载安装JDK 本次操作我们这里采用JDK8和JDK11两个版本来进行示范操作参考的官方下载链接如下: 官网下载:https://www.oracle.com/java/technologies/downloads/ 下载之后进行安装即可 二、配置JDK 1.系统变量 在系统变量中新建变量,变量名JAVA_HOME,JAVA_HOME11,JAVA_HOME8如图所示: 这里JAVA_HOME11,JAVA_HOME8的变量值是你安装JDK8或JDK11的路径,到该目录级别就可,JDK8也是如此,如图所示: 之后设置Path里面的变量,加上%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin; 最好加在最前面,因为安装JDK11之后会生成一个变量,该变量级别高于自己设置的这个变量,需要你在通过新建之后(新建后在最底下,通过后右边向上移动按钮向上移动)将我们新添加的变量通过向上移动,移动到C:\WINDOWS;C:\Program Files (x86)\Common Files\Oracle\Java\javapath和C:\Program Files\Common Files\Oracle\Java\javapath以及C:\WINDOWS\System32变量之上。 **必须做:**另外需要注意的是你需要将C:\Program Files (x86)\Common Files\Oracle\Java\javapath(或者C:\Program Files\Common Files\Oracle\Java\javapath)目录下的以下图片中的文件删除,请注意删除的是只有这三个的,如图: 如果下面图片这样的则不删除 删除完之后通过命令 javac -version和java -version查看是否匹配。 如果要更改版本,你只需要修改JAVA_HOME变量中的值即可 要修改为JDK8版本,则将JAVA_HOME变量值改为%JAVA_HOME8%即可 要修改为JDK11版本,则将JAVA_HOME变量值改为%JAVA_HOME11%即可 修改后需要重新打开cmd再用javac -version和java -version查看,才可以看到是否修改成功。 希望上面这些简单操作能够顺利帮你了解到怎么切换多版本JDK进行开发,加油。———————————————— 原文链接:https://blog.csdn.net/qq_45775798/article/details/122665158
-
java.security.InvalidKeyException: Illegal key size 1、为什么会出现这个报错? JDK中包含有JRE(Java Runtime Environment,即:Java运行环境),JRE中包括Java虚拟机(Java Virtual Machine)、Java核心类库和支持文件,而我们今天要说的主角就在Java的核心类库中。在Java的核心类库中有一个JCE(Java Cryptography Extension),JCE是一组包,它们提供用于加密、密钥生成和协商以及 Message Authentication Code(MAC)算法的框架和实现,所以这个是实现加密解密的重要类库。 在我们安装的JRE目录下有这样一个文件夹:%JAVE_HOME%\jre\lib\security(%JAVE_HOME%是JDK安装路径),其中包含有两个.jar文件:“local_policy.jar ”和“US_export_policy.jar”,这两个jar包就是我们JCE中的核心类库了。JRE中自带的“local_policy.jar ”和“US_export_policy.jar”是支持128位密钥的加密算法,而当我们要使用256位密钥算法的时候,已经超出它的范围,无法支持,所以才会报:“java.security.InvalidKeyException: Illegal key size”的异常。 2、解决方案 一般针对jdk1.6,jdk1.7, jdk1.8,这个问题可以去博客 https://blog.csdn.net/dafeige8/article/details/76019911 找到解决方案,需要下载对应的“local_policy.jar ”和“US_export_policy.jar”两个文件替换掉自己%JAVE_HOME%\jre\lib\security文件夹下对应的原文件; 不过针对jdk1.8.0_151版本稍微不一样,%JAVE_HOME%\jre\lib\security下多了个policy文件夹: policy下有2个文件夹limited和unlimited: ├── limited │ ├── local_policy.jar │ └── US_export_policy.jar └── unlimited ├── local_policy.jar └── US_export_policy.jar 从Java 1.8.0_151和1.8.0_152开始, 提供了 无限制强度管辖策略, 默认是不启用的,简单修改下配置即可启用: 在 %JAVE_HOME%\jre\lib\security 文件夹下找到 java.security 文件,在826行左右会有如下配置: #crypto.policy=unlimited 去掉前面的#,重启Java应用即可。 ———————————————— 原文链接:https://blog.csdn.net/angellee1988/article/details/123588983
-
语言更新和改进JEP 432:记录模式(第二预览版) — 支持用户嵌套记录模式和类型模式,以创建强大、声明性且可组合的数据导航和处理形式,从而增强 Java 语言。这有助于开发人员扩展模式匹配,以实现更复杂和可定制的数据查询,从而提高工作效率。JEP 433:Switch 模式匹配(第四预览版 ) — 通过将模式匹配扩展到 switch,可以针对多个模式测试表达式,每个模式都有特定的操作,让用户可以安全、简洁地表达面向数据的复杂查询。增强 switch 表达式和语句的表达性、适用性有助于提高开发人员的工作效率。Project Loom 预览版/孵化器功能JEP 429:作用域值(孵化器) — 支持在线程内和跨线程共享不可变数据,这些数据优先于线程局部变量,尤其是在使用大量虚拟线程时。这可提高易用性、性能、稳定性和安全性。JEP 436:虚拟线程(第二预览版) — 通过向 Java 平台引入轻量级虚拟线程,显著减少编写、维护和观察高吞吐量并发应用的工作量。虚拟线程让开发人员可以轻松使用现有的 JDK 工具和技术,对并发应用进行故障排除、调试和分析,进而加快应用开发速度。JEP 437:结构化并发(二次孵化阶段) — 通过将运行于不同线程中的多个任务视为一个工作单元,简化多线程编程。这可帮助开发团队简化错误处理和取消工作,并提高可靠性和可观测性。Project Panama 预览版功能JEP 434:外部函数和内存 API(第二预览版) — Java 程序可以更容易地与 Java 运行时之外的代码和数据进行互操作。通过有效调用外部函数(即 Java Virtual Machine [JVM] 之外的代码),以及安全地访问外部内存(即不受 JVM 管理的内存),该特性支持 Java 程序无需 Java Native Interface 即可调用本地库和处理原生数据,从而提高易用性、性能、灵活性和安全性。JEP 438:矢量 API(五次孵化阶段) — 允许以一种在运行时,可靠地编译为支持的 CPU 架构上的向量指令方式表达向量计算,从而实现优于等效标量计算的性能。Java 20 是甲骨文公司工程师与全球 Java 开发人员社区成员通过 OpenJDK 社区 和 Java Community Process (JCP) 共同合作的成果。Java 20 除了推出了新的增强功能,也获得 Java Management Service 的支持,这是一项新的 Oracle 云基础设施远程软件服务(Oracle Cloud Infrastructure, OCI)原生服务,可帮助管理本地部署或任何云端的 Java 运行时和应用程序。支持 Java 客户和全球生态系统转载自https://www.sohu.com/a/657667541_121118996
-
老铁们,JDK 20 / Java 20 正式发布了,这版本号简直超神了。。JDK 20 是一个短期维护版本,将获得六个月的支持。尽管如此,但它仍然可用于生产环境中。根据开发计划,下一个 LTS 版本就是将于 2023 年 9 月发布的 JDK 21。此版本包括 7 个 JEP(都处于不同的孵化和预览阶段),以及数百个较小的功能增强和数千个错误修复: 429:Scoped Values (Incubator)432:Record Patterns (Second Preview)433:Pattern Matching for switch (Fourth Preview)434:Foreign Function & Memory API (Second Preview)436:Virtual Threads (Second Preview)437:Structured Concurrency (Second Incubator)438:Vector API (Fifth Incubator)作用域值(Scoped Values)进入孵化阶段引入 Scoped Values,它可以在线程内和线程间共享不可变数据。它们优于线程局部变量,尤其是在使用大量虚拟线程时。记录模式 (Record Patterns) 进入第 2 预览阶段Record Patterns 可对 record 的值进行解构,Record patterns 和 Type patterns 通过嵌套能够实现强大的、声明性的、可组合的数据导航和处理形式。switch 模式匹配 (Pattern Matching for switch) 进入第 4 预览阶段用 switch 表达式和语句的模式匹配,以及对模式语言的扩展来增强 Java 编程语言。将模式匹配扩展到 switch 中,允许针对一些模式测试表达式,这样就可以简明而安全地表达复杂的面向数据的查询。外部函数和内存 API (Foreign Function & Memory API) 进入第 2 预览阶段引入一个 API,通过它,Java 程序可以与 Java 运行时之外的代码和数据进行互操作。通过有效地调用外部函数,以及安全地访问外部内存,该 API 使 Java 程序能够调用本地库并处理本地数据,而不会像 JNI 那样有漏洞和危险。虚拟线程 (Virtual Threads) 进入第 2 预览阶段为 Java 引入虚拟线程,虚拟线程是 JDK 实现的轻量级线程,它在其他多线程语言中已经被证实是十分有用的,比如 Go 中的 Goroutine、Erlang 中的进程。虚拟线程避免了上下文切换的额外耗费,兼顾了多线程的优点,简化了高并发程序的复杂,可以有效减少编写、维护和观察高吞吐量并发应用程序的工作量。结构化并发 (Structured Concurrency) 进入第 2 孵化阶段JDK 19 引入了结构化并发,这是一种多线程编程方法,目的是为了通过结构化并发 API 来简化多线程编程,并不是为了取代 java.util.concurrent。结构化并发将不同线程中运行的多个任务视为单个工作单元,从而简化错误处理、提高可靠性并增强可观察性。也就是说,结构化并发保留了单线程代码的可读性、可维护性和可观察性。向量 API (Vector API) 进入第 5 孵化阶段向量计算由对向量的一系列操作组成。向量 API 用来表达向量计算,该计算可以在运行时可靠地编译为支持的 CPU 架构上的最佳向量指令,从而实现优于等效标量计算的性能。向量 API 的目标是为用户提供简洁易用且与平台无关的表达范围广泛的向量计算。更多详情可查看:https://openjdk.org/projects/jdk/20/下载:https://jdk.java.net/20/转载自https://mp.weixin.qq.com/s/7WovwVFiXtFIAtaO871UHw
-
新公司转正述职报告,花了些时间准备了ppt和讲稿,这里分享一下 述职报告 时间过得很快,转眼就已经三个月了,三个月时间不长,完成的工作也有限,但是在这些工作中,我也学到了很多,现在对这三个月的工作和自己的收获做一个简短汇报。总共分为四部分:工作小结、个人收获、自我思考还有未来展望。 1.工作小结 首先,工作小结 这是我入职一周时试用期跟进表中填写的试用期目标,可以说试用期的工作主要是围绕着这些目标来进行的,时间过得很快,现在已经是入职第十二周了,我也已经写了十一份周报了,现在再回过头来看这份试用期目标,我个人觉得可能没有百分百优秀的完成,比如需求设计上还有很多不足。但是也基本上能达到我对自己的要求与期望了。 下面是工作内容,基本上就是写设计文档,写接口然后测试,改bug,当然前期最主要的工作内容还是熟悉和学习。熟悉项目的业务和项目代码以及我们开发与上线的流程。这个地方还要说一下我们的uu加速器,前几堂课是关于开发环境的课,对我有很大帮助。程序员的工作主要当然还是以写代码为主。 我们项目的迭代速度还是比较快的,基本上是每周都有上线,没有新需求的时候也会有一些以前功能的优化需求。这三个月我主要参与的迭代就是这些:balabalabala 你参与的项目完成的功能,写一下 2.个人收获 这一段时间里有工作上的收获,知识的丰富,经验的增长,同时也暴露出很多问题和不足,下面是我的个人收获,我在技术上和经验上分别作了一些总结。 首先这三个月的开发工作也让我学习到一些新的技术知识,比如 balabalabala……………… 相比于技术上的学习,我觉得我在经验上的收获可能更多的,可能也是因为我这方面的不足也比较多,进步空间比较大。 首先在功能设计上要提升全局观念,沟通意识,先有规划再写代码,开发前的设计阶段真的很重要,设计逻辑理顺了,剩下的开发就相对比较轻松。确定方案的时候要结合线上的使用情况,不能只看开发和测试环境就拍脑袋。 代码上要考虑到所写的代码是否有走弯路,自己所做的模块是否能有效的和其他同事所做的模块相融合,加强代码的优化,争取所写的每一句代码都能发挥起作用。我的问题就比较疏于代码优化,对系统性能要求不高;全局考虑欠缺,写一步算一步,以至于走了很多弯路。最大的不足就是粗心大意考虑问题不够细致,不太注重细节。这可能也是我个人的性格原因,最后体现在工作上,也体现在代码上。认识到了以后现在也正在慢慢修改。 在需求上,因为我们项目经常会有功能优化的需求,对以前的代码做一些改动,这些其实都还好,因为有产品的业务需求会比较清楚,如果是进行代码优化的话就需要自己去把这一块的业务逻辑理清再修改,否则就容易想当然,字段在我眼里就只是字段没有什么特别的,但是可能他在这块的业务逻辑上是需要特殊处理的,这些在优化之前都是需要搞清楚的。 最后就是要注重沟通了,咱们的项目都不是一个人去开发的,沟通一定要及时到位。 3.自我思考 在新环境中的一些思考与感悟,以及对所属业务的理解和对公司、部门的理解。 首先是我的一些工作心得,这虽然不是我的第一份工作,但是其实算是真正意义上我一个人进入一个完全陌生的大团队里去工作,当然现在已经非常熟了。有导师时常在周围点播我帮助我成长,有小伙伴一起相互促进共同进步。这种新的定位让我感受到在工作之中团队的重要性,在团队里每个人各司其职,任何一个人掉队都有可能导致机器瘫痪,只有协同合作,才能实现我们的共同价值。 然后就是责任感,我觉得我们应该对自己的代码负责,对自己的项目负责,首先要避免出问题,出了问题要主动承担,发现错误认识错误改正错误,团队协作,出了问题从来都不是一个人的事,所以发现项目中不足的地方也要主动的去优化提出。 在公司上,balabalabala…………写下你对公司业务的理解,公司文化的感受啥的 4.未来展望 未来会继续学习,加深对业务,行业的理解。同时在技术上也要继续努力,在写好业务代码的同时深入学习,能尽快成为独当一面的工程师,往资深架构的目标持续努力。 为了实现这些目标,要保持自我复盘,强化优势,持续学习,注重业务实践,这些事情看起来可能很简单,但是能持之以恒的做下去应该也不容易,我会继续这样要求自己,也欢迎大家监督。 最后,试用期完成的工作有限,我也有很多不足之处,处理问题的方式也有待提高,未来我会总结反思和保持积极向上的态度,认证细心的处理好每段代码,努力在公司实现自己的目标,和公司一起成长。 都是套话,修改一下就可以直接用,ppt打开演讲者模式照着稿子念,舒服 文中的PPT已经上传了,需要的可以自行下载 点击下载 https://download.csdn.net/download/weixin_48356746/86796115 that’s all ———————————————— 版权声明:本文为CSDN博主「LxyrichBos」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_48356746/article/details/122249379
-
多线程实现方法1.继承 java.lang.Thread,重写 run方法// 定义线程类 public class MyThread extends Thread{ public void run(){ } } // 创建线程对象 MyThread t = new MyThread(); // 启动线程。 t.start();2.实现 java.lang.Runnable 接口,实现run方法// 定义一个可运行的类 public class MyRunnable implements Runnable { public void run(){ } } // 创建线程对象 Thread t = new Thread(new MyRunnable()); // 启动线程 t.start();或者用匿名类public class ThreadTest04 { public static void main(String[] args) { // 创建线程对象,采用匿名内部类方式。 Thread t = new Thread(new Runnable(){ @Override public void run() { for(int i = 0; i < 100; i++){ System.out.println("t线程---> " + i); } } }); // 启动线程 t.start(); for(int i = 0; i < 100; i++){ System.out.println("main线程---> " + i); } } }Thread和Runnable的区别如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。总结:实现Runnable接口比继承Thread类所具有的优势:1):适合多个相同的程序代码的线程去处理同一个资源2):可以避免java中的单继承的限制3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类线程状态转换1、新建状态(New):新创建了一个线程对象。2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种: (一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。(注意,sleep是不会释放持有的锁)5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。线程同步1、synchronized关键字的作用域有二种: 1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法; 2)是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/区块/},它的作用域是当前对象;3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;
-
集合的分类集合List和Set都继承于Collection,都是单个储存元素的都是可以迭代的。1. List特点是是可重复、有序的,存入和迭代取出的次序相同。List的子类又有ArrayList、LinkedList、Vector。ArrayList底层采用数组结构存储,适合做查询笔试和频繁的增删,单线程操作效率高,随机增删效率低,多线程不安全。 初始10,按照1.5倍扩容Vector和ArrayList底层原理相同,但是使用sychorinized保证了多线程安全,效率低少使用。 初始10,按照2倍扩容LinkedList底层采用双向链表结构存储元素,增删效率高,随机查找效率低。不能通过数学表达式计算被查找元素的内存地址,每一次查找都是从头节点开始遍历,直到找到为止。所以LinkedList集合检索/查找的效率较低。2. Set特点是元素无序不可重复,不能按照index取值,适合做数据字典。HashSet底层是一个哈希表(散列表),实际是一个HashMap。SortedSet特点是存取无序且不可重复,但是存的元素可以自动按照大小排列。TreeSet继承于SortedSet,底层是一个二叉树TreeMap。3. Map双列集合Map,和Collection集合没有关系,Map集合以key-value的形式储存元素,key和value都是存储java对象的内存地址,所有Map集合的特点都是无序不可重复。Map和Set集合存储元素的特点相同。HashMap底层是哈希表,非线程安全,在JDK8后如果哈希表单向元素超过8个就编程红黑树结构,红黑树的节点数量小于6个又编程单项链表结构,为的是提交检索效率。 初始容量是16,按照2倍扩容。HashTable底层也是哈希表,用sychorinized是线程安全的,key和value不允许为null。 初始容量11,按照 原容量*2+1 方式扩容。Properties继承于HashTable,线程安全,key和value只能是String类型。常用方法1.Collection的常用方法方法名说明boolean add(E e)添加元素到集合的末尾(追加)boolean remove(Object o)删除指定的元素,成功则返回true(底层调用equles)void clear()清空集合boolean contains(Object o)判断元素在集合中是否存在,存在则返回true(底层调用equles)boolean isEmpty()判断集合是否为空,空则返回trueint size()返回集合中元素个数Iterator iterator()迭代器2.ArrayList的常用方法方法名说明public ArrayList()创建一个空集合public boolean add(E e)将指定的参数元素追加到集合的末尾public void add(int index ,E e)在集合的指定位置添加指定的元素(插入元素)public void addAll(E object)用于将指定集合中所有元素添加到当前集合中public boolean remove(Object o)删除指定的元素,成功则返回truepublic E remove(int index)删除指定索引位置的元素,返回被删除的元素public E set(int index,E e)修改指定索引位置的元素,返回修改前的元素public E get(int index)获取指定索引对应的元素public int size()获取结合中元素个数3.Map的基本方法方法名说明V put(K key,V value)设置键值对V remove(Object key)删除元素void clear()清空集合boolean containsKey(Object key)判断键是否存在,存在则返回trueboolean containsValue(Object value)判断值是否存在,存在则返回trueboolean isEmpty()判断集合是否为空int size()获取集合元素个数
上滑加载中
推荐直播
-
华为云码道 × 仓颉编程:工程化AI编码探索2026/05/27 周三 19:00-21:00
刘俊杰-华为云仓颉语言专家/李炎-华为云码道技术专家/王智鹏-OpenCangjie开源社区发起人
本场直播围绕华为云仓颉语言与华为云码道的深度结合,展示华为云智能编程从零基础到高效落地的完整生态能力。以华为云码道为引擎,仓颉语言为载体,带给大家日常提效、趣味创新到极速量产的开发体验。
回顾中
热门标签