addShop error addShopImg error:null 添加图片为空
异常: "C:\Program Files\Java\jdk1.8.0_171\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\IDEA\IntelliJ IDEA 2019.1\lib\idea_rt.jar=4429:D:\IDEA\IntelliJ IDEA 2019.1\bin" -Dfile.encoding=UTF-8 -classpath "D:\IDEA\IntelliJ IDEA 2019.1\lib\idea_rt.jar;D:\IDEA\IntelliJ IDEA 2019.1\plugins\junit\lib\junit-rt.jar;D:\IDEA\IntelliJ IDEA 2019.1\plugins\junit\lib\junit5-rt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\rt.jar;E:\imooc\projects\o2o\target\test-classes;E:\imooc\projects\o2o\target\classes;D:\maven\maven-3.6.0\repository\junit\junit\4.12\junit-4.12.jar;D:\maven\maven-3.6.0\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\maven\maven-3.6.0\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\maven\maven-3.6.0\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\maven\maven-3.6.0\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;D:\maven\maven-3.6.0\repository\org\springframework\spring-core\4.3.7.RELEASE\spring-core-4.3.7.RELEASE.jar;D:\maven\maven-3.6.0\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\maven\maven-3.6.0\repository\org\springframework\spring-beans\4.3.7.RELEASE\spring-beans-4.3.7.RELEASE.jar;D:\maven\maven-3.6.0\repository\org\springframework\spring-context\4.3.7.RELEASE\spring-context-4.3.7.RELEASE.jar;D:\maven\maven-3.6.0\repository\org\springframework\spring-aop\4.3.7.RELEASE\spring-aop-4.3.7.RELEASE.jar;D:\maven\maven-3.6.0\repository\org\springframework\spring-expression\4.3.7.RELEASE\spring-expression-4.3.7.RELEASE.jar;D:\maven\maven-3.6.0\repository\org\springframework\spring-jdbc\4.3.7.RELEASE\spring-jdbc-4.3.7.RELEASE.jar;D:\maven\maven-3.6.0\repository\org\springframework\spring-tx\4.3.7.RELEASE\spring-tx-4.3.7.RELEASE.jar;D:\maven\maven-3.6.0\repository\org\springframework\spring-web\4.3.7.RELEASE\spring-web-4.3.7.RELEASE.jar;D:\maven\maven-3.6.0\repository\org\springframework\spring-webmvc\4.3.7.RELEASE\spring-webmvc-4.3.7.RELEASE.jar;D:\maven\maven-3.6.0\repository\org\springframework\spring-test\4.3.7.RELEASE\spring-test-4.3.7.RELEASE.jar;D:\maven\maven-3.6.0\repository\javax\servlet\javax.servlet-api\3.1.0\javax.servlet-api-3.1.0.jar;D:\maven\maven-3.6.0\repository\com\fasterxml\jackson\core\jackson-databind\2.8.7\jackson-databind-2.8.7.jar;D:\maven\maven-3.6.0\repository\com\fasterxml\jackson\core\jackson-annotations\2.8.0\jackson-annotations-2.8.0.jar;D:\maven\maven-3.6.0\repository\com\fasterxml\jackson\core\jackson-core\2.8.7\jackson-core-2.8.7.jar;D:\maven\maven-3.6.0\repository\commons-collections\commons-collections\3.2\commons-collections-3.2.jar;D:\maven\maven-3.6.0\repository\org\mybatis\mybatis\3.4.2\mybatis-3.4.2.jar;D:\maven\maven-3.6.0\repository\org\mybatis\mybatis-spring\1.3.1\mybatis-spring-1.3.1.jar;D:\maven\maven-3.6.0\repository\mysql\mysql-connector-java\8.0.16\mysql-connector-java-8.0.16.jar;D:\maven\maven-3.6.0\repository\com\google\protobuf\protobuf-java\3.6.1\protobuf-java-3.6.1.jar;D:\maven\maven-3.6.0\repository\c3p0\c3p0\0.9.1.2\c3p0-0.9.1.2.jar;D:\maven\maven-3.6.0\repository\net\coobird\thumbnailator\0.4.8\thumbnailator-0.4.8.jar;D:\maven\maven-3.6.0\repository\com\github\penggle\kaptcha\2.3.2\kaptcha-2.3.2.jar;D:\maven\maven-3.6.0\repository\com\jhlabs\filters\2.0.235-1\filters-2.0.235-1.jar;D:\maven\maven-3.6.0\repository\commons-fileupload\commons-fileupload\1.3.2\commons-fileupload-1.3.2.jar;D:\maven\maven-3.6.0\repository\commons-io\commons-io\2.2\commons-io-2.2.jar;D:\maven\maven-3.6.0\repository\redis\clients\jedis\2.9.0\jedis-2.9.0.jar;D:\maven\maven-3.6.0\repository\org\apache\commons\commons-pool2\2.4.2\commons-pool2-2.4.2.jar" com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit4 com.imooc.o2o.Service.ShopServiceTest,testAddShop 三月 17, 2020 12:19:05 上午 org.springframework.test.context.support.DefaultTestContextBootstrapper getDefaultTestExecutionListenerClassNames 信息: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener] 三月 17, 2020 12:19:05 上午 org.springframework.test.context.support.DefaultTestContextBootstrapper getTestExecutionListeners 信息: Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@2d3fcdbd, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@617c74e5, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@6537cf78, org.springframework.test.context.support.DirtiesContextTestExecutionListener@67b6d4ae, org.springframework.test.context.transaction.TransactionalTestExecutionListener@34b7bfc0, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@366e2eef] 三月 17, 2020 12:19:05 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [spring/spring-dao.xml] 三月 17, 2020 12:19:05 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [spring/spring-service.xml] 三月 17, 2020 12:19:06 上午 org.springframework.context.support.GenericApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.GenericApplicationContext@8bd1b6a: startup date [Tue Mar 17 00:19:06 CST 2020]; root of context hierarchy 三月 17, 2020 12:19:06 上午 com.mchange.v2.log.MLog <clinit> 信息: MLog clients using java 1.4+ standard logging. 三月 17, 2020 12:19:07 上午 com.mchange.v2.c3p0.C3P0Registry banner 信息: Initializing c3p0-0.9.1.2 [built 21-May-2007 15:04:56; debug? true; trace: 10] 三月 17, 2020 12:19:08 上午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource getPoolManager 信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 2, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 10000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1hge13ca81raucym13t1s5p|10e31a9a, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.cj.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1hge13ca81raucym13t1s5p|10e31a9a, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/o2o?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 40, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 10, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ] 2020-03-17 00:19:09.331 [main] DEBUG com.imooc.o2o.dao.ShopDao.insertShop - ==> Preparing: insert into tb_shop(owner_id, area_id, shop_category_id, shop_name, shop_desc, shop_addr, phone, shop_img, priority, create_time, last_edit_time, enable_status, advice) VALUES (?,?,?,?, ?,?,?,?,?, ?,?, ?,?) 2020-03-17 00:19:09.384 [main] DEBUG com.imooc.o2o.dao.ShopDao.insertShop - ==> Parameters: 1(Long), 2(Integer), 1(Long), 测试的店铺名称11(String), test11(String), test11 addr(String), 1875583105(String), null, null, 2020-03-17 00:19:09.308(Timestamp), 2020-03-17 00:19:09.308(Timestamp), 0(Integer), 审核中(String) 2020-03-17 00:19:09.386 [main] DEBUG com.imooc.o2o.dao.ShopDao.insertShop - <== Updates: 1 com.imooc.o2o.exceptions.ShopOperationException: addShop error addShopImg error:null at com.imooc.o2o.service.impl.ShopServiceImpl.addShop(ShopServiceImpl.java:63) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) at com.sun.proxy.$Proxy23.addShop(Unknown Source) at com.imooc.o2o.Service.ShopServiceTest.testAddShop(ShopServiceTest.java:50) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) 三月 17, 2020 12:19:09 上午 org.springframework.context.support.GenericApplicationContext doClose 信息: Closing org.springframework.context.support.GenericApplicationContext@8bd1b6a: startup date [Tue Mar 17 00:19:06 CST 2020]; root of context hierarchy Process finished with exit code -1
代码: @Service public class ShopServiceImpl implements ShopService { @Autowired private ShopDao shopDao; @Override @Transactional public ShopExecution addShop(Shop shop, File shopImg) { //空值判断 if(shop ==null){ return new ShopExecution(ShopStateEnum.NULL_SHOP); } try{ //给店铺信息赋值初始值 shop.setEnableStatus(0); shop.setCreateTime(new Date()); shop.setLastEditTime(new Date()); int effectedNum = shopDao.insertShop(shop); //添加店铺信息 if(effectedNum <=0){ //使用ShopOperationException抛出异常,创建店铺失败时候,事务才会回滚。而Exception 不会回滚 throw new ShopOperationException("创建店铺失败"); }else { if(shopImg !=null){ //存储图片 try { addShopImg(shop, shopImg); System.out.println("shop:"+shop); System.out.println("shopImg:"+shopImg); }catch (Exception e){ throw new ShopOperationException("addShopImg error:"+e.getMessage()); } //更新店铺的图片地址 effectedNum = shopDao.updateShop(shop); if(effectedNum <=0){ throw new ShopOperationException("update shopImg addr error"); } } } }catch (Exception e){ throw new ShopOperationException("addShop error "+e.getMessage()); } return new ShopExecution(ShopStateEnum.CHECK,shop); } private void addShopImg(Shop shop, File shopImg) { //获取shop图片目录的相对值路径 String dest = PathUtils.getShopImagePath(shop.getShopId()); try { String shopImgAddr = ImageUtil.generateThumbnail(shopImg, dest); shop.setShopImg(shopImgAddr); }catch ( Exception e){ e.getMessage(); } } }
@Test public void testAddShop(){ Shop shop = new Shop(); PersonInfo owner = new PersonInfo(); Area area = new Area(); ShopCategory shopCategory = new ShopCategory(); owner.setUserId(1L); area.setAreaId(2); shopCategory.setShopCategoryId(1L); shop.setOwner(owner); shop.setArea(area); shop.setShopCategory(shopCategory); shop.setShopName("测试的店铺名称11"); shop.setShopDesc("test11"); shop.setShopAddr("test11 addr"); shop.setPhone("1875583105"); shop.setCreateTime(new Date()); shop.setEnableStatus(ShopStateEnum.CHECK.getState()); shop.setAdvice("审核中"); File shopImg = new File("E:/imooc/bgImage.jpg"); ShopExecution se = shopService.addShop(shop,shopImg); assertEquals(ShopStateEnum.CHECK.getState(),se.getState()); } @Test public void test(){ File shopImg = new File("E:/imooc/bgImage.jpg"); System.out.println(shopImg); }
package com.imooc.o2o.util; /** * @author zcc * @date 2020/3/16 21:35 * @description */ public class PathUtils { public static String seperator = System.getProperty("file.seperator"); public static String getImgBasePath() { String os = System.getProperty("os.name"); String basePath = ""; if (os.toLowerCase().startsWith("win")) { basePath = "E:/imooc/image/"; } else { basePath = "/home/xiangze/image/"; } basePath = basePath.replace("/", seperator); return basePath; } public static String getShopImagePath(long shopId) { String imagePath = "upload/item/shop/" + shopId + "/"; return imagePath.replace("/", seperator); } }
package com.imooc.o2o.util; import net.coobird.thumbnailator.Thumbnails; import net.coobird.thumbnailator.geometry.Positions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.multipart.commons.CommonsMultipartFile; import javax.imageio.ImageIO; import java.io.File; import java.io.IOException; import java.net.URLDecoder; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random; /** * @author zcc * @date 2020/3/10 16:52 * @description */ public class ImageUtil { private static String basePath = Thread.currentThread().getContextClassLoader().getResource("").getPath(); private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); private static final Random r = new Random(); private static Logger logger = LoggerFactory.getLogger(ImageUtil.class); /** * 将CommonsMultipartFile 装换成file类 * @param cFile * @return */ public static File transferCommonsMultipartFile(CommonsMultipartFile cFile){ File newFile = new File(cFile.getOriginalFilename()); try { cFile.transferTo(newFile); } catch (IOException e) { logger.error(e.toString()); e.printStackTrace(); } return newFile; } /** * 处理缩略图,并返回新生成图片的相对值路径 * @param thumbnail * @param targetAddr * @return */ public static String generateThumbnail(File thumbnail,String targetAddr){ String realFileName =getRandomFileName(); String extension =getFileExtension(thumbnail); makeDirPath(targetAddr); String relativeAddr = targetAddr +realFileName+extension; logger.error("current relativeAddr is:"+relativeAddr); File dest = new File (PathUtils.getImgBasePath()+ relativeAddr); logger.error("current complete addr is:"+PathUtils.getImgBasePath()+relativeAddr); try{ Thumbnails.of(thumbnail).size(200,200) .watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(basePath+"/watermark.jpg")),0.25f) .outputQuality(0.8f).toFile(dest); }catch (IOException e){ logger.error(e.toString()); e.printStackTrace(); } return relativeAddr; } /** * 创建目标路径所涉及的目录,即/home/work/xiangzai/xx.jpg * 那么 home work xiangzai 这三个文件夹都得自动创建 * @param targetAddr */ private static void makeDirPath(String targetAddr) { String realFileParentPath = PathUtils.getImgBasePath()+targetAddr; File dirPath = new File(realFileParentPath); if(!dirPath.exists()){ dirPath.mkdirs(); } } /** * 获取输入文件扩展名 * @param thumbnail * @return */ private static String getFileExtension(File thumbnail) { String originalFileName = thumbnail.getName(); return originalFileName.substring(originalFileName.lastIndexOf(".")); } /** * 生成随机文件名,当前时间年月日时分秒加5位随机数 */ private static String getRandomFileName() { //获取随机5位数 int rannum = r.nextInt(89999)+10000; String nowTimeStr = sDateFormat.format(new Date()); return nowTimeStr+rannum; } public static void main(String[] args) throws IOException { basePath = basePath.substring(1,basePath.lastIndexOf("/"))+"/watermark.jpg"; System.out.println(basePath); String inputfile ="E:/imooc/bgImage.jpg"; inputfile = URLDecoder.decode(inputfile,"utf-8"); String targetfile = "E:/imooc/bgImage2.jpg"; targetfile = URLDecoder.decode(targetfile,"utf-8"); Thumbnails.of(new File(inputfile)).size(200,200) .watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File("E:\\imooc\\projects\\o2o\\src\\main\\resources\\watermark.jpg")),0.25f) .outputQuality(0.8f).toFile(targetfile); } }
怎么回事?
35
收起
正在回答 回答被采纳积分+1
5回答
相似问题
登录后可查看更多问答,登录/注册
4. SSM到Spring Boot入门与综合实战
- 参与学习 人
- 提交作业 323 份
- 解答问题 8263 个
本阶段将带你学习主流框架SSM,以及SpringBoot ,打通成为Java工程师的最后一公里!
了解课程
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星