作成中の
wicketで
なんかないか
それを
稼働環境の 情報
Java Version 、
- OS
OS X El Capitan バージョン 10.11.6
- Java
java -version ------------------------------ java version "1.8.0_45" Java(TM) SE Runtime Environment (build 1.8.0_45-b14) Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode) ------------------------------
- Wicket
<dependency> <groupId>org.apache.wicket</groupId> <artifactId>wicket-core</artifactId> <version>7.4.0</version> </dependency>
まず、 サイトマップに 関する ガイドラインに 記載が ある。 一般的な サイトマップXMLの 仕様に ついて
サイトマップの
サイトマップの
以下、
1 つの
サイトマップには サイズが 10 MB、 URL は 50,000 件以下に する。 サイトマップの
形式は、 [XML]、 [RSS、 mRSS、 Atom 1.0]、 [テキスト]、 [Google サイト] の 4つ サイトマップ インデックス ファイル を
作る 場合は、 サイトマップは 送信しなくて 良い。 サイトマップ インデックス ファイルの
xmlフォーマットは、 サイトマップの xmlフォーマットと 少し違う サイトマップ ファイルを
http://example.co.jp/catalog/sitemap.xml に 置いた 場合は、
http://example.co.jp/catalog/ から始まる URL を 含める ことができるが、
http://example.co.jp/images/ から始まる URL を 含める ことは できない。
Example の 挙動の 確認
sitemap indexファイルの
実際に
1. pom.xml に 依存関係を 追加
<!-- https://mvnrepository.com/artifact/org.wicketstuff/wicketstuff-sitemap-xml --> <dependency> <groupId>org.wicketstuff</groupId> <artifactId>wicketstuff-sitemap-xml</artifactId> <version>7.4.0</version> </dependency>
2. SiteMap.java を 作成する
core/ExampleSiteMap.java at master · wicketstuff/coreを
SiteMap.javaを
3. Applicationクラスで、 SiteMap を 登録
Application#mountResource()
で、
// ------------------------------------------------------------------------------- // SiteMap // ------------------------------- mountResource("sitemap.xml", new SiteMap());
4. デプロイして、 出力を 確認
ローカル環境にhttp://127.0.0.1:18080/sitemap.xml
に
以下の
sitemapと
※サーバを
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <script/> <sitemap> <loc> http://127.0.0.1:18080/sitemap.xml?sourceindex=0&offset=0 </loc> <lastmod>2016-10-29</lastmod> </sitemap> <sitemap> <loc> http://127.0.0.1:18080/sitemap.xml?sourceindex=0&offset=1000 </loc> <lastmod>2016-10-29</lastmod> </sitemap> ... </sitemapindex>
続いて、http://127.0.0.1:18080/sitemap.xml?sourceindex=0&offset=0
に
以下の
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <script/> <url> <loc>http://127.0.0.1:18080/sitemap.xml?number=0</loc> <lastmod>2016-10-29</lastmod> <changefreq>weekly</changefreq> <priority>0.5</priority> </url> <url> <loc>http://127.0.0.1:18080/sitemap.xml?number=1</loc> <lastmod>2016-10-29</lastmod> <changefreq>weekly</changefreq> <priority>0.5</priority> </url> ... </urlset>
sitemap.xml が
sitemap.xml の
※50000件以上の
sitemap インデックスファイルに
サイトマップに<wbr>関する<wbr>ガイドライン
の
Exmaple実装を、
アプリケーションで
前提事項
作ってるのは
音楽フェスの サイトで、 音楽フェスごとの ページと、 アーティストページが ある フェスの
ページ、 アーティストページとも 記事の インデックスIDは RDBに 保存している RDBからは
JPAで データを 取得する
Example を 変更
Exampleから
1. Sitemap.java
変更点は
- getDataSources()で
IOffsetSiteMapEntryIterable の、 2つ 実装クラスを 返すようにした。
フェスごとの
フェスページの
アーティストページの
返すようにしました。
- getDomain() は
オーバーライド
親クラスSiteMapIndex.java の
public String getDomain() { if (domain == null) { final Request rawRequest = RequestCycle.get().getRequest(); if (!(rawRequest instanceof WebRequest)) { throw new WicketRuntimeException("sitemap.xml generation is only possible for http requests"); } WebRequest wr = (WebRequest) rawRequest; domain = "http://" + ((HttpServletRequest) wr.getContainerRequest()).getHeader("host"); } return domain; }
HTTP headerの
nginxで
リソースバンドルから、
package xyz.monotalk.sitemap; import com.google.api.client.repackaged.com.google.common.base.Strings; import org.apache.wicket.extensions.sitemap.IOffsetSiteMapEntryIterable; import org.apache.wicket.extensions.sitemap.SiteMapIndex; import java.util.MissingResourceException; import java.util.ResourceBundle; /** * SiteMap */ public class SiteMap extends SiteMapIndex { private static final long serialVersionUID = 7074357449807043532L; @Override public IOffsetSiteMapEntryIterable[] getDataSources() { return new IOffsetSiteMapEntryIterable[]{ new FestivalOffsetSiteMapEntryIterable(getDomain()), new ArtistOffsetSiteMapEntryIterable(getDomain()) }; } /** * getDomain * * @return */ public String getDomain() { String domain = null; try { domain = ResourceBundle.getBundle("WicketApplication").getString("domainName"); } catch (MissingResourceException e) { // Do Nothing... return super.getDomain(); } if (Strings.isNullOrEmpty(domain)) { return super.getDomain(); } return domain; } }
続いて、
2. FestivalOffsetSiteMapEntryIterable.java
以下、
RDBからの
取得は 遅延初期化する
SiteMap Entry クラスでは、何回も Entryを 取得する 必要は ないように 思ったので、
1回 ELEMENTS_PER_BLOCK数分のレコードを 取得して、 その レコードを 使い回すように しています。 Guice の
@Transactional アノテーションを 付与しているので、 close() では 何もしない。
@Transactionnal をつけて おくと、 勝手に EntiryManager.remove()まで 実行してくれるので、
close()メソッドでは何もしないように 実装しました。 BasicSiteMapEntryBuilder を
作った。
BasicSiteMapEntry のコンストラクタに 4つ 引数を 渡すのが 何かしっくりこなかったので、
Builderクラスを作成しました。
※これは趣味の 話かと 思います。 JPAの
リポジトリクラスは、 class内で Injector経由で Inject
FestivalOffsetSiteMapEntryIterableクラス内で、Injector経由で Injectしています。
@Inject アノテーションでInjectする 場合は、 mountResourceメソッド実行時に 以下のように インスタンスを、
生成する必要が あります。
mountResource("/sitemap.xml", InjectorHolder._new(SiteMap.class));
package xyz.monotalk.sitemap; import lombok.NonNull; import org.apache.wicket.extensions.sitemap.IOffsetSiteMapEntryIterable; import org.apache.wicket.extensions.sitemap.ISiteMapEntry; import org.apache.wicket.request.cycle.RequestCycle; import org.apache.wicket.request.mapper.parameter.PageParameters; import xyz.monotalk.models.rdb.entity.Festival; import xyz.monotalk.models.rdb.repository.FestivalRepository; import xyz.monotalk.inject.initialize.InjectorHolder; import xyz.monotalk.pages.festival.detail.FestivalDetailPage; import java.util.Date; import java.util.List; /** * FestivalOffsetSiteMapEntryIterable */ public class FestivalOffsetSiteMapEntryIterable implements IOffsetSiteMapEntryIterable { private FestivalRepository repository = InjectorHolder._new(FestivalRepository.class); private int festivalTotalCount = -1; private Date changedDate = null; private String domain = null; private static final int ELEMENTS_PER_BLOCK = 1000; /** * FestivalOffsetSiteMapEntryIterable * * @param domain */ public FestivalOffsetSiteMapEntryIterable(@NonNull String domain) { this.domain = domain; } @Override public int getUpperLimitNumblocks() { if (festivalTotalCount == -1) { festivalTotalCount = repository.getRecordCount().intValue(); } return (int) Math.ceil((double) festivalTotalCount / ELEMENTS_PER_BLOCK); } /** * fullUrlFrom * * @param charSequence * @return */ private String fullUrlFrom(@NonNull CharSequence charSequence) { return this.domain + "/" + charSequence.toString(); } @Override public int getElementsPerSiteMap() { return ELEMENTS_PER_BLOCK; } @Override public Date changedDate() { if (changedDate == null) { changedDate = repository.getMaxUpdateDate(); } return changedDate; } @Override public SiteMapIterator getIterator(final int startIndex) { return new SiteMapIterator() { int numCalled = 0; private List<Festival> festivals = null; /** * getFestivals * @param limit * @param offset * @return */ private List<Festival> getFestivals(int limit, int offset) { if (festivals == null) { festivals = repository.findAllByLimitAndOffset(limit, offset); } return festivals; } /** * hasNext * @return */ public boolean hasNext() { return numCalled <= ELEMENTS_PER_BLOCK && numCalled < getFestivals(ELEMENTS_PER_BLOCK, startIndex).size(); } /** * next * @return */ public ISiteMapEntry next() { Festival elem = getFestivals(ELEMENTS_PER_BLOCK, startIndex).get(numCalled); PageParameters pageParameters = new PageParameters(); pageParameters.add("id", elem.getId()); numCalled++; final CharSequence url = RequestCycle.get() .mapUrlFor(FestivalDetailPage.class, pageParameters) .toString(); return new BasicSiteMapEntryBuilder(fullUrlFrom(url)) .setModified(elem.getUpdateDate()) .setFrequency(ISiteMapEntry.CHANGEFREQ.WEEKLY) .setPriority(0.5).createBasicSiteMapEntry(); } /** * remove */ public void remove() { throw new UnsupportedOperationException("not possible here.."); } public void close() { // Do Nothing... // @Transactional 付与で勝手にcloseされるので何もしない } }; } }
3. BasicSiteMapEntryBuilder.java
これは、
Builerクラスです。。
package xyz.monotalk.sitemap; import lombok.NonNull; import org.apache.wicket.extensions.sitemap.BasicSiteMapEntry; import org.apache.wicket.extensions.sitemap.ISiteMapEntry; import java.util.Date; /** * BasicSiteMapEntryBuilder */ public class BasicSiteMapEntryBuilder { private String url; private Date modified; private double priority; private ISiteMapEntry.CHANGEFREQ frequency; private static final double DEFAULT_PRIORITY = 0.5; public BasicSiteMapEntryBuilder(@NonNull String url) { this.url = url; modified = new Date(); priority = DEFAULT_PRIORITY; frequency = ISiteMapEntry.CHANGEFREQ.WEEKLY; } public BasicSiteMapEntryBuilder setModified(@NonNull Date modified) { this.modified = modified; return this; } public BasicSiteMapEntryBuilder setPriority(double priority) { if (priority > 1.0) { priority = 1.0; } if (priority < 0.0) { priority = 0.0; } this.priority = priority; return this; } public BasicSiteMapEntryBuilder setFrequency(@NonNull ISiteMapEntry.CHANGEFREQ frequency) { this.frequency = frequency; return this; } public BasicSiteMapEntry createBasicSiteMapEntry() { return new BasicSiteMapEntry(this.url, this.modified, this.priority, this.frequency); } }
sitemap index ファイル に
少し
※SiteMapIndex.java に
補足. Wicket wiki 記載の Sitemap.xml 生成方法
Wicket wiki にも、
補足と
リンクは
wicketstuff の
Wicket の
この
この
また、
って
以上です。
コメント